PageSourceSearch

https://www.okeypets.com/assets/js/unit/content-list.js?v=1

js okeypets.com collected 2026-10-07 10:29:15 UTC 66,325 bytes, 1,717 lines download raw bytes

1class ScriptContentList extends Script {
2	constructor(params) {
3		super(params)
4		// 产品列表组件dom
5		this.$unit = document.getElementById(`${this.attrId}`)
6		if (!this.$unit) return
7		this.$unitList = this.$unit.querySelector('.unit-content-list')
8		// tab选项卡dom
9		this.$tabList = this.$unit.querySelectorAll('.nav-item')
10		this.$tabTypeItem = this.$unit.querySelectorAll('[tab-type]')
11		// 无数据时显示Nodata
12		this.$noData = this.$unit.querySelector(".page_no_data")
13		// 产品选项卡内容dom
14		this.pageInfo = JSON.parse(this.utilts.htmlDecode(params.pageInfo))
15		this.colInfo = JSON.parse(this.utilts.htmlDecode(params.colInfo))
16		this.config = JSON.parse(this.utilts.htmlDecode(params.config))
17		this.relate_list = JSON.parse(this.utilts.htmlDecode(params.relate_list))
18		this.config.hover_img = (params.hoverImg === 'true')
19		this.content_type = params.content_type
20		this.content_type_list = params.content_type.split(',')
21		this.modal = null
22		this.info = window.app.info
23		this.open_hover = params.open_hover // hover动画   fadeInUp,fadeOutUp,
24    this.$carouselEl = this.$unitList
25		// console.log('this.config', this.config);
26		// 视频播放方式
27    if (this.config.video) {
28      let methodMap = {
29        default: this.config.video.method,
30        md: this.config.video.method_md,
31        xl: this.config.video.method_xl
32      }
33      this.method = methodMap[this.utilts.getScreen()]
34    }
35
36    if (this.config.swiper.is_swiper) {
37      this.initSwiperEvents()
38    }
39		this.sizeMap = {
40			default: this.config.page_size_default,
41			md: this.config.page_size_md,
42			xl: this.config.page_size_xl
43		}
44		this.bg_hover_linear = params.bg_hover_linear
45		this.page_size = Number(this.sizeMap[this.utilts.getScreen()]) || 6
46		this.all_total = JSON.parse(this.utilts.htmlDecode(params.all_total))
47		this.all_page_category_id = JSON.parse(this.utilts.htmlDecode(params.all_page_category_id))
48		this.tab_list = JSON.parse(this.utilts.htmlDecode(params.tab_list))
49		this.allPage = {}
50		this.tab_list.forEach((val, index) => {
51			this.allPage[val] = {
52				page_number: 1,
53				page_total: 0,
54				page_count: 1,
55				page_category_id: '',
56				limit_page_number: 1
57			}
58			if (this.all_total[val]) {
59				this.allPage[val].page_total = this.all_total[val]
60				this.allPage[val].page_count = Math.ceil(this.all_total[val] / this.page_size)
61				this.allPage[val].limit_page_number = Math.ceil(100 / this.page_size)
62			}
63			if (this.all_page_category_id[index]) this.allPage[val].page_category_id = this.all_page_category_id[index]
64		})
65		// console.log('this.allPage---', this.allPage);
66	}
67
68  render() {
69    if (this.$unit._zoom && this.$unit._zoom.render) {
70      this.$unit._zoom.render()
71    }
72  }
73
74	async init() {
75		if (!this.$unit) return
76    if (!this.viewsData) {
77      if (window.app.info.site.viewsData) {
78        this.viewsData = window.app.info.site.viewsData
79      } else {
80        try {
81          this.viewsData = window.app.info.site.viewsData =  await loadJSModule('/dist/template/views-data.js')
82        } catch (error) {
83          console.error('模块加载失败:', error);
84        }
85      }
86    }
87    if (!window.ejs) {
88      await new Load('/assets/plugins/ejs.min.js')
89    }
90		const that = this
91		this.content_type_list.forEach(item => {
92			if (item !== 'page_content') {
93				this.initLoadData(item)
94			}
95		})
96		if (this.config.load_type === 2) {
97			// 滚动加载
98			this.initObserver() 
99		} else if (this.config.load_type === 1) {
100			// 点击加载
101			this.initLoadEvent()
102		}
103		if (!this.utilts.checkDesign()) this.initFilter()
104		this.initMoreData()
105		this.initHoverContent()
106		this.initInquiry()
107    // this.initVideoData()
108    this.initVideo()
109    this.initLink()
110		this.initResize()
111		this.initQuoteList()
112		const initContent = () => {
113			// 等待contentRender完成再进行初始化
114			setTimeout(function () {
115				that.initHoverImg()
116			}, 300)
117		}
118		if (this.utilts.checkDesign() || (window.app && window.app.hookEvents && window.app.hookEvents['hookInitContentRender'])) {
119			initContent();
120			// window.addEventListener('hookInitContentRender', initContent, {
121			// 	once: false
122			// })
123		} else {
124			window.addEventListener('hookInitContentRender', initContent, {
125				once: true
126			})
127		}
128
129		// 初始选项卡切换事件
130		this.initTabEvent()
131		// 放大图片
132		if (this.config.target === 'zoom') {
133			await new Load('/assets/plugins/zoom.js')
134      this.$unit._zoom = new ZoomBuilder({
135				attrId: this.attrId,
136				dom: this.$unit,
137				selector: '.unit-list__image[zoom-img="true"]',
138				titleSelector: ".unit-list__title",
139				boxClass: 'list-zoom-box'
140			})
141		}
142    this.initPrevClick()
143	}
144	// 标签详情页筛选排序
145	initFilter() {
146		const filterText = this.$unit.querySelector('.unit-content-list__filter-text')
147		if (!filterText) return
148		filterText.addEventListener('click', () => {
149			if (filterText.classList.contains('active')) {
150				filterText.classList.remove('active')
151			} else {
152				filterText.classList.add('active')
153			}
154		})
155		document.querySelector('body').addEventListener('click', (e) => {
156			if (!e.target.classList.contains('unit-content-list__filter-text') && !e.target.parentNode?.classList.contains('unit-content-list__filter-text')){
157				if (filterText.classList.contains('active')) filterText.classList.remove('active')
158			}
159		})
160		window.addEventListener('scroll', () => {
161			if (filterText.classList.contains('active')) filterText.classList.remove('active')
162		})
163		const filterListType = this.$unit.querySelectorAll('.unit-content-list__filter-type span')
164		if (filterListType && filterListType.length) {
165			filterListType.forEach((val, index) => {
166				val.addEventListener('click', async () => {
167					if (!val.classList.contains('active')) {
168						filterListType.forEach(val => val.classList.remove('active'))
169						val.classList.add('active')
170						if (index === 1) this.$unit.querySelector('.unit-list__items').classList.add('unit-list__items-single-row')
171						else this.$unit.querySelector('.unit-list__items').classList.remove('unit-list__items-single-row')
172					}
173				})
174			})
175		}
176		const dropdownItems = this.$unit.querySelectorAll('.unit-content-list__filter-dropdown-item')
177		const listItems = this.$unit.querySelector('.unit-list__items')
178		const currentReadMore = this.$unit.querySelector(`.unit-content-list_more .more-btn`)
179		if (dropdownItems && dropdownItems.length) {
180			dropdownItems.forEach(val => {
181				val.addEventListener('click', async () => {
182					if (!val.classList.contains('active')) {
183						dropdownItems.forEach(val => val.classList.remove('active'))
184						val.classList.add('active')
185						filterText.querySelector('.unit-content-list__filter-default').innerText = this.utilts.$t(val.innerText)
186						this.allPage[this.tab_list[0]].page_number = 1
187					  const	sortValue = val.getAttribute('data-value')
188						const list = await this.getVideoData(this.tab_list[0], sortValue)
189						if (currentReadMore.classList.contains('put-away')) {
190							currentReadMore.querySelector('span').innerHTML = this.utilts.$t('Load More')
191							currentReadMore.classList.remove('put-away')
192							listItems.classList.remove('hidden-load-item')
193						}
194						this.rederInnerContent(list, this.$unit, 'replace')
195					}
196				})
197			})
198		}
199	}
200	initLoadEvent() {
201		// 分页
202		// if (this.tab_list.length > 1 && this.content_type === 'video_column') {
203		// 	this.tab_list.forEach(val => {
204		// 		this.renderPagination(val, this.$unit.querySelector(`[tab-type=${val}]`))
205		// 		// this.$unit.querySelector(`[tab-type=${val}] .unit-content-list_more`)
206		// 	})
207		// } else {
208		// 	this.renderPagination(this.tab_list[0], this.$unit)
209		// }
210		// 点击加载更多
211		if (this.config.load_type === 1) {
212			if (this.tab_list.length > 1) {
213				this.tab_list.forEach(val => {
214					this.changeDom(val, this.$unit.querySelector(`[tab-type=${val}]`))
215				})
216			} else {
217				this.changeDom(this.tab_list[0], this.$unit)
218			}
219		}
220	}
221	changeDom(val, dom) {
222		const listItems = dom.querySelector('.unit-list__items')
223		if (listItems) {
224			const maxSize = Math.max(this.sizeMap.xl, this.sizeMap.md, this.sizeMap.default)
225			const hideCount = maxSize - this.page_size
226			const childrenArray = Array.from(listItems.children)
227			if (hideCount > 0 && childrenArray.length > hideCount) {
228				listItems.classList.remove('temp-items') 
229				childrenArray.slice(-hideCount).forEach(child => child.remove());
230			}
231		}
232		const currentReadMore = dom.querySelector(`.unit-content-list_more .more-btn`)
233		const allContentList = dom.querySelector(`.unit-content-list_all`)
234		if (!currentReadMore) return
235		const currentPage = this.allPage[val]
236		// console.log('currentPage', currentPage, this.attrId)
237		if (currentPage.page_count > 1) {
238			currentReadMore.parentNode.classList.remove('d-none')
239		}
240		currentReadMore.addEventListener('click', async () => {
241			if (this.config.limit_count && currentPage.page_total > this.config.limit_count && currentPage.page_number === Math.ceil(this.config.limit_count / this.page_size)) return
242			if (currentReadMore.classList.contains('put-away')) {
243				currentReadMore.querySelector('span').innerHTML = this.utilts.$t('Load More')
244				currentReadMore.classList.remove('put-away')
245				listItems.classList.add('hidden-load-item')
246				return false
247			}
248			if (currentPage.page_number === currentPage.page_count) {
249				currentReadMore.querySelector('span').innerHTML = this.utilts.$t('Put Away')
250				currentReadMore.classList.add('put-away')
251				listItems.classList.remove('hidden-load-item')
252				return false
253			}
254			currentPage.page_number++
255			const list = await this.getVideoData(val)
256			this.rederInnerContent(list, dom)
257			if (this.config.limit_count) {
258				const resCount = currentPage.page_total  > this.config.limit_count ? this.config.limit_count : currentPage.page_total
259				const limitPage = Math.ceil(resCount / this.page_size)
260				if (currentPage.page_number === limitPage) {
261					if (currentPage.page_total  > this.config.limit_count) allContentList.classList.remove('d-none')
262					currentReadMore.parentNode.classList.add('d-none')
263				}
264			}
265			if (currentPage.page_number === currentPage.page_count && !this.config.limit_count && !this.config.swiper.is_swiper) {
266				currentReadMore.querySelector('span').innerHTML = this.utilts.$t('Put Away')
267				currentReadMore.classList.add('put-away')
268			}
269			if (currentPage.page_number === currentPage.page_count && this.config.swiper.is_swiper) {
270				currentReadMore.parentNode.classList.add('d-none')
271			}
272		})
273	}
274	rederInnerContent(data, dom, method='append') {
275		const listItems = dom.querySelector('.unit-list__items')
276    const currentLength = dom.querySelector('.unit-list__items').children.length
277		const newHtml = data.map((item, index) => {
278      if (item.video_id) {
279        item = new ContentItemVideo(item)
280      } else if (item.article_id) {
281        item = new ContentItemArticle(item)
282			} else {
283        item = new ContentItemDefault(item)
284      }
285			return `
286				<div
287					animate
288					class="${this.bg_hover_linear} animate unit-list__item swiper-slide ${!item.img ? 'no-image' : ''} col-${this.colInfo.cols_col} col-md-${this.colInfo.cols_md} col-xl-${this.colInfo.cols_xl} ${method !== 'replace' ? 'load-item' : ''}"
289					data-media="${item.title}"
290					composing-xl="${this.config.composing_xl}"
291					${item.title === 'Wechat' ? `data-wechatCode=${item.href}` : ''}
292				>
293					<div class="unit-list__a"
294            data-href="${this.config.target==='block'?'javascript:;':globalThis.Server.getRinseHref(item.href, window.app.info.site)}"
295            data-target="${this.config.target==='block'?'_self':this.config.target || item.target || '_self'}"
296          >
297						<div
298							class="unit-list__item-inner d-flex ${this.config.composing_xl ? '' : 'flex-column'}"
299						>
300							${this.renderInner(item, currentLength + index)}
301						</div>
302					</div>
303				</div>
304			`
305		}).join('')
306		// 分页
307		if (method === 'replace') {
308			listItems.innerHTML = newHtml
309		} else {
310			// 滚动加载更多
311			listItems.innerHTML += newHtml
312		}
313    // 图片加载
314    this.$unit.querySelectorAll('[lazy-src]').forEach(item => {
315      if (!item.getAttribute('src')) {
316        new LazyImg(item, { img_using_avif: window.app.siteConfig?.img_using_avif }).loadImg()
317      }
318    })
319    if (this.content_type === 'article_list') {
320			// 视频初始化
321    	this.initVideo()
322		}
323    // link
324    this.initLink()
325		// 轮播更新
326    if (this.config.swiper.is_swiper) {
327			// this.$unit.querySelectorAll('.swiper-container').forEach(item => {
328			// 	item.swiper?.destroy()
329			// })
330			this.$unit.querySelectorAll('[carousel]').forEach(item => this.utilts.interObserver(item, () => new Carousel(item, this.config.swiper), false))
331			this.initSwiperEvents()
332		}
333	}
334	renderInner(item, index) {
335    let contentItem = item
336    let selfPackage = this.utilts.checkDesign() ? design.packages[this.attrId] : window.app.info.windowCtxState.packages[this.attrId]
337    if (item.cover_url && (item.content_type === 'video' || (item.content_type === 'material' && /\.mp4/i.test(item.cover_url) || item.is_embed_video))) {
338      // let contentItem = new ContentItemVideo(item)
339      return this.getEjsResult(`/package/components/unit-content-list-card__video`, { package: selfPackage, item: contentItem, from: 'content-list', subIndex: index })
340    } else {
341      // let contentItem = new ContentItemDefault(item)
342      return this.getEjsResult(`/package/components/unit-content-list-card__image`, { package: selfPackage, item: contentItem, from: 'content-list', subIndex: index })
343    }
344	}
345  /*
346  * 获取HTML
347  */
348  getEjsResult(path, data) {
349    data = this.getEjsParmes(data)
350    const ejsOptions = { client: true, delimiter: '?' }
351    const viewString = this.viewsData[path]
352    const viewCompile = window.ejs.compile(viewString, ejsOptions)
353    const viewHtml = viewCompile(data, null, (sonPath, sonData) => {
354      let thisViewString = this.viewsData[sonPath]
355      
356      if (thisViewString) {
357        if (thisViewString.indexOf('include(') >= 1) {
358          thisViewString = this.getEjsResult(sonPath, sonData)
359        }
360        sonData = this.getEjsParmes(sonData)
361        const template = window.ejs.render(thisViewString, sonData, ejsOptions)
362        return template
363      } else {
364        console.error(`${sonPath} 未找到对应的html。`)
365      }
366    })
367    return viewHtml
368  }
369  /** 模坂引擎参数 */
370  getEjsParmes(data) {
371    if (this.utilts.checkDesign()) {
372      return {
373        ...ctx.state,
374        ...data,
375        getViewsPath: path => path,
376        translate: text => text
377      }
378    }
379    const state = {
380      ...window.app.info.windowCtxState,
381      site: window.app.info.site,
382      page: window.app.info.page,
383      $t: window.app.utilts.$t
384    }
385    return {
386      ctx: {state},
387      ...state,
388      ...data,
389      getViewsPath: path => path,
390      translate: text => text
391    }
392  }
393	initObserver() {
394		// if (!this.utilts.checkDesign()) {
395		// }
396		const listBox = this.$unit.querySelector('.unit-content-list')
397		function throttle(func, limit) {
398			let lastFunc;
399			let lastRan;
400			return function() {
401				const context = this;
402				const args = arguments;
403				if (!lastRan) {
404					func.apply(context, args);
405					lastRan = Date.now();
406				} else {
407					clearTimeout(lastFunc);
408					lastFunc = setTimeout(function() {
409							if ((Date.now() - lastRan) >= limit) {
410									func.apply(context, args);
411									lastRan = Date.now();
412							}
413					}, limit - (Date.now() - lastRan));
414				}
415			}
416		}
417		const loadEle = this.$unit.querySelector('.loading-inner')
418		const targetElement = this.$unit
419		let isLoading = false; // 加载状态锁
420		let lastScrollTop = 0
421		const checkScroll = async () => {
422			let currentScrollTop = window.pageYOffset || document.documentElement.scrollTop;
423			const elementBottom = targetElement.getBoundingClientRect().bottom;
424			// console.log('elementBottom', elementBottom, 'innerHeight', window.innerHeight)
425			const currentPageObj = this.allPage[this.tab_list[0]]
426			if (currentScrollTop > lastScrollTop && elementBottom && elementBottom <= window.innerHeight + 20 && !isLoading && currentPageObj.page_count > 1 && currentPageObj.page_number < currentPageObj.page_count) {
427				console.log('加载更多数据----');
428				listBox.classList.add('scroll-list')
429				isLoading = true
430				loadEle.classList.remove('d-none')
431				currentPageObj.page_number++
432				const sortValue = this.$unit.querySelector('.content-set .change-set span.active').getAttribute('data-value')
433				const list = await this.getVideoData(this.tab_list[0], sortValue)
434				this.rederInnerContent(list, this.$unit)
435				setTimeout(() => {
436					isLoading = false
437					loadEle.classList.add('d-none')
438					listBox.classList.remove('scroll-list')
439				}, 500)
440			}
441			lastScrollTop = currentScrollTop; // 更新上一次的滚动位置
442		}
443		window.addEventListener('scroll', throttle(checkScroll, 200));
444		const setItems = this.$unit.querySelectorAll('.content-set .change-set span')
445		if (setItems && setItems.length) {
446			setItems.forEach(val => {
447				val.addEventListener('click', async () => {
448					if (!val.classList.contains('active')) {
449						setItems.forEach(val => val.classList.remove('active'))
450						val.classList.add('active')
451						this.allPage[this.tab_list[0]].page_number = 1
452					  const	sortValue = val.getAttribute('data-value')
453						const list = await this.getVideoData(this.tab_list[0], sortValue)	
454						this.rederInnerContent(list, this.$unit, 'replace')
455					}
456				})
457			})
458		}
459	}
460	renderPagination(val, dom) {
461		const paginationDom = dom.querySelector(".unit-content-list_pagination")
462		if (!paginationDom) return
463		window.changePagination = (e, num) => {
464			if ((e.target.classList.contains('iconfont') && e.target.parentNode.parentNode.classList.contains('disabled')) || ((e.target.classList.contains('base-pagination__link') && e.target.parentNode.classList.contains('disabled')))) return
465			this.onPagination(num, val, paginationDom)
466		}
467		let resHtml = ``
468		if (val && this.allPage[val].page_total) {
469			resHtml = `
470				<nav class="base-pagination">
471					<ul class="base-pagination__items">
472						<li class="base-pagination__item base-pagination__item--prev ${this.allPage[val].page_number === 1 ? 'disabled' : ''}">
473							<a class="base-pagination__link" href="javascript:;" onClick="changePagination(event, ${this.allPage[val].page_number - 1})"><span class="iconfont icon-action-left-lighter"></span></a>
474						</li>
475			`
476			if (this.allPage[val].page_number > 2) {
477				resHtml += `
478					<li class="base-pagination__item ${this.allPage[val].page_count > 3 ? 'base-pagination__item-first' : ''}">
479						<a class="base-pagination__link" href='javascript:;' onClick="changePagination(event, 1)">1</a>
480					</li>
481				`
482			}
483			if (this.allPage[val].page_number > 2 && this.allPage[val].page_number - 2 > 1) { 
484				resHtml += `
485					<li class="base-pagination__item base-pagination__item-more disabled">
486						<a class="base-pagination__link base-pagination__link-more" href="javascript:;">...</a>
487					</li>
488				`
489			}
490			if (this.allPage[val].page_number > 1) {
491				resHtml += `
492					<li class="base-pagination__item">
493						<a class="base-pagination__link" href="javascript:;" onClick="changePagination(event, ${this.allPage[val].page_number - 1})">${this.allPage[val].page_number - 1}</a>
494					</li>
495				`
496			}
497			resHtml += `
498				<li class="base-pagination__item active unit-pagination-active">
499					<a class="base-pagination__link" href="javascript:;" onClick="changePagination(event, ${this.allPage[val].page_number})">${this.allPage[val].page_number}</a>
500				</li>
501			`
502			if (this.allPage[val].page_count - this.allPage[val].page_number > 1) {
503				resHtml += `
504					<li class="base-pagination__item">
505						<a class="base-pagination__link" href="javascript:;" onClick="changePagination(event, ${this.allPage[val].page_number + 1})">${this.allPage[val].page_number + 1}</a>
506					</li>
507				`
508			}
509			if (this.allPage[val].page_number == 1 && this.allPage[val].page_count > 3) {
510				resHtml += `
511					<li class="base-pagination__item base-pagination__item-third">
512						<a class="base-pagination__link" href="javascript:;" onClick="onPagination(event, 3)">3</a>
513					</li>
514				`
515			}
516			if (this.allPage[val].page_count - this.allPage[val].page_number > 2) {
517				resHtml += `
518					<li class="base-pagination__item base-pagination__item-more disabled">
519						<a class="base-pagination__link" href="javascript:;">...</a>
520					</li>
521				`
522			}
523			if (this.allPage[val].page_count !== this.allPage[val].page_number && this.allPage[val].page_count > this.allPage[val].page_number) {
524				resHtml += `
525					<li class="base-pagination__item ${this.allPage[val].page_count > 3 && this.allPage[val].page_count - this.allPage[val].page_number !== 1 ? 'base-pagination__item-last' : ''}">
526						<a class="base-pagination__link" href="javascript:;" onClick="changePagination(event, ${this.allPage[val].page_count})">${this.allPage[val].page_count}</a>
527					</li>
528				`
529			}
530			resHtml += `
531				<li class="base-pagination__item base-pagination__item--next ${this.allPage[val].page_number >= this.allPage[val].page_count ? 'disabled' : ''} page-next">
532					<a class="base-pagination__link" href="javascript:;" onClick="changePagination(event, ${this.allPage[val].page_number + 1})"><span class="iconfont icon-action-left-lighter"></span></a>
533				</li>
534			`
535		}
536		paginationDom.innerHTML = resHtml
537	}
538	async	onPagination(num, val, dom) {
539		this.allPage[val].page_number = num
540		const list = await this.getVideoData(val)
541		this.rederInnerContent(list, dom)
542	}
543	/** 获取视频数据 */
544  getVideoData(val, default_sort) {
545    return new Promise((resolve, reject) => {
546			let resSize = this.page_size
547			if (this.config.limit_count && this.allPage[val].page_total > this.config.limit_count) {
548				const limitPage = Math.ceil(this.config.limit_count / this.page_size)
549				if (limitPage === this.allPage[val].page_number) {
550					resSize = this.config.limit_count - (this.allPage[val].page_number - 1) * this.page_size
551				}
552			}
553      let params = {
554        site_id: window.app.info.site.site_id,
555        language_code: window.app.info.site.language_code,
556				page_size: resSize,
557				page_number: this.allPage[val].page_number,
558				status: 1,
559				show_status: 1,
560				sort: 'update_time desc'
561      }
562			if (this.content_type === 'short_video') {
563				params.type = 1
564			}
565			if (this.content_type === 'specify_video') {
566				params.id = this.relate_list.join(',')
567			}
568			if (this.content_type === 'video_column') {
569				if (this.tab_list.length > 1) params.page_category_id = this.allPage[val].page_category_id
570				else params.page_category_id = this.relate_list.join(',') || ''
571			}
572			if (this.content_type === 'article_list') {
573				params.content_type = 3
574				params.is_delete = 0
575			}
576			if (this.config?.allow_content_tag) {
577				params.tag_id = this.pageInfo.tag_id
578			}
579			params.sort = this.config.sort || 'update_time desc'
580			if (default_sort) params.sort = default_sort
581			const apiUrl = this.content_type === 'article_list' ? '/article/list-page-by-search' : '/video/list-page-by-search'
582			const prefix = this.content_type === 'article_list' ? 'jmc' : 'qqt'
583      this.utilts.request({
584        url: apiUrl,
585        method: 'POST',
586        prefix,
587        params
588      }).then(res => {
589        resolve(res.data.list)
590      })
591      .catch(error => reject(error))
592    })
593  }
594	/**
595	 * 初始化轮播图相关事件
596	 */
597	initSwiperEvents() {
598		const that = this;
599		/**
600		 * 修复当前轮播图异常图片
601		 * 检查当前活动幻灯片中的图片,如果src为空但有lazy-src属性,则设置src
602		 */
603		const fixEmptySrc = () => {
604			if (this.$carouselEl.swiper) {
605				const swiper = this.$carouselEl.swiper;
606				const activeSlide = swiper.slides[swiper.activeIndex];
607				if (activeSlide) {
608					activeSlide.querySelectorAll('img[lazy-src][src=""], img[lazy-src]:not([src])').forEach(img => {
609						const imgSrc = img.getAttribute('data-src') || img.getAttribute('lazy-src');
610						if (imgSrc) {
611							// 设置异常图片的src
612							img.setAttribute('src', imgSrc);
613						}
614					});
615				}
616			}
617		};
618
619		/**
620		 * 当前播放模式视频自动播放
621		 * 重置所有视频,并播放当前活动幻灯片中的视频
622		 */
623		const _autoplayVideo = () => {
624			if (this.$carouselEl.swiper) {
625				const swiper = this.$carouselEl.swiper;
626				swiper.slides.forEach((slide, index) => {
627					const $baseVideo = slide.querySelector('.base-video');
628					if ($baseVideo) {
629						$baseVideo.resetVideo && $baseVideo.resetVideo();
630						const CURRENT_PLAY = '2'; //当前播放
631						const videoConfig = this.config.video;
632						if (videoConfig?.autoplay && Number(videoConfig.autoplay) > 0 && this.method === CURRENT_PLAY && index === swiper.activeIndex) {
633							setTimeout(() => {
634								$baseVideo.playVideo && $baseVideo.playVideo();
635							});
636						}
637					}
638				});
639			}
640		}
641		// 轮播结束重置视频
642		const _autoResetVideo = () => {
643			if (this.$carouselEl.swiper) {
644				const swiper = this.$carouselEl.swiper;
645				swiper.slides.forEach((slide, index) => {
646					const $baseVideo = slide.querySelector('.base-video');
647					if ($baseVideo) {
648						if (index !== swiper.activeIndex) {
649							$baseVideo.resetVideo && $baseVideo.resetVideo();
650						}
651					}
652				})
653			}
654		}
655
656		if (this.config.swiper.is_swiper) {
657			/**
658			 * 监听Swiper初始化
659			 * 设置Swiper初始化后需要执行的事件
660			 */
661			const listenSwiperInit = () => {
662				// 处理swiper init
663				const _eventsInitSwiper = [];
664				this.$carouselEl._eventsInitSwiper = _eventsInitSwiper;
665				if (this.$carouselEl.swiper) {
666					_eventsInitSwiper.forEach(func => {
667						if (func instanceof Function) {
668							func();
669						}
670					});
671				}
672			};
673
674			/**
675			 * 监听Swiper幻灯片切换
676			 * 设置幻灯片切换时需要执行的事件
677			 */
678			const listenSwiperSlide = () => {
679				/**
680				 * 轮播图切换时执行事件
681				 * @type {Array}
682				 * @private
683				 */
684				const _eventsOnSlide = [fixEmptySrc];
685				const _eventsSlideEnd = []
686				const _eventsSlideStart = []
687				const videoConfig = this.config.video;
688				const CURRENT_PLAY = '2'; //当前播放
689				if (videoConfig && this.method === CURRENT_PLAY) {
690					const videoAutoplay = videoConfig.autoplay && parseInt(videoConfig.autoplay) > 0;
691					if (videoAutoplay) {
692						_eventsSlideStart.push(_autoplayVideo);
693					}
694					_eventsSlideEnd.push(_autoResetVideo);
695				}
696				// [carousel]层
697				this.$carouselEl._eventsOnSlide = _eventsOnSlide;
698				this.$carouselEl._eventsSlideStart = _eventsSlideStart;
699				this.$carouselEl._eventsSlideEnd = _eventsSlideEnd;
700			};
701
702			listenSwiperInit();
703			listenSwiperSlide();
704		}
705	}
706
707
708	initPrevClick() {
709    const gifHoverImages = this.$unit.querySelectorAll('.unit-list-hover__image')
710    if (gifHoverImages.length) {
711      gifHoverImages.forEach(val => {
712        val.addEventListener('click', () => {
713					if (this.method === '2') val.classList.add('d-none')
714          val.parentNode.parentNode.click()
715        })
716      })
717    }
718  }
719	initVideoData(currentDom) {
720		const doms = currentDom ? currentDom.querySelectorAll('.unit-list__img[video-gif]') : (
721			this.$unitList.querySelectorAll('.unit-list__video[video-gif]') || this.$unitList.querySelectorAll('.unit-list__img[video-gif]')
722		)
723		if (doms.length) {
724			doms.forEach(item => {
725				this.renderHoverImg(item, currentDom ? true : false)
726				const h_dom = item.querySelector('.unit-list-hover__image')
727				const originImg = item.children[0].querySelector('.base-image__item') // hover原图的效果
728				const video_gif = item.getAttribute('video-gif')
729				item.parentNode.onmouseover = e => {
730					if (h_dom && h_dom.classList.contains('hover_img_before_load')) {
731						h_dom.classList.remove('hover_img_before_load')
732					}
733					originImg.classList.add('opacity0')
734					item.querySelector('.base-video__play')?.classList.add('d-none')
735					item.parentNode?.querySelector('.base-video__play').classList.add('d-none')
736				}
737				item.parentNode.onmouseout = e => {
738					originImg.classList.remove('opacity0')
739					if (h_dom) {
740						h_dom.classList.add('hover_img_before_load')
741					}
742					item.querySelector('.base-video__play')?.classList.remove('d-none')
743					item.parentNode?.querySelector('.base-video__play').classList.remove('d-none')
744				}
745			})
746		}
747	}
748	renderHoverImg(node, flag) {
749		const video_gif = node.getAttribute('video-gif')
750		node.setAttribute('hover-img', true)
751		node.setAttribute('video-gif', video_gif)
752		let hoverImgEl = ''
753		if (node.querySelector('.unit-list-hover__image img')) {
754			hoverImgEl = node.querySelector('.unit-list-hover__image img')
755			hoverImgEl.setAttribute('lazy-src', video_gif)
756			const wrapper = flag ? node.children[0].cloneNode(true) : node.children[0].querySelector('.base-video__thumb').cloneNode(true)
757			wrapper.querySelector('.base-image__item').innerHTML = hoverImgEl.outerHTML
758			node.querySelector('.unit-list-hover__image').innerHTML = wrapper.outerHTML
759			const hoverImg = node.querySelector('.unit-list-hover__image img')
760			new LazyImg(hoverImg)
761			// node.querySelector('.unit-list-hover__image img').setAttribute('lazy-type', '')
762		} else {
763			hoverImgEl = document.createElement('div')
764			// unit-list-hover__image animate__animated hover_img_before_load
765			hoverImgEl.classList.add('unit-list-hover__image', 'hover_img_before_load')
766			const wrapper = flag ? node.children[0].cloneNode(true) : node.children[0].querySelector('.base-video__thumb').cloneNode(true)
767			wrapper.querySelector('.base-image__item').innerHTML = `<img class="base-image__img img-fluid" lazy-src="${video_gif}"  alt="">`
768			hoverImgEl.innerHTML = wrapper.outerHTML
769			const hoverImg = hoverImgEl.querySelector('.unit-list-hover__image img')
770			new LazyImg(hoverImg)
771			if (flag) node.appendChild(hoverImgEl)
772			else node.querySelector('.base-video__preview').appendChild(hoverImgEl)
773			// node.querySelector('.unit-list-hover__image img').setAttribute('lazy-type', '')
774		}
775	}
776	initMoreData() {
777		const tabHeader = this.$unit.querySelector('.tab-header')
778		const contentSet = this.$unit.querySelector('.content-set')
779    if (this.utilts.getScreen() === 'default' && !this.utilts.checkDesign() && tabHeader) {
780			const parents = this.utilts.getParentsByAttr(this.$unit, 'package-group', 'cell')
781			const videoInner = parents[0].querySelector('.video-inner')
782			let bottomVal = document.querySelector('[package-type="header"]').offsetHeight
783			if (videoInner) {
784				const videoRect = videoInner.getBoundingClientRect()
785				bottomVal = videoRect.bottom
786			}
787			tabHeader.style.top = bottomVal + 'px'
788		}
789    if (this.utilts.getScreen() === 'default' && !this.utilts.checkDesign() && contentSet) {
790			const headerHeight = document.querySelector('[package-type="header"]').offsetHeight
791			contentSet.style.top = headerHeight + 'px'
792		}
793		const moreEle = this.$unitList.querySelector('.show-more-box')
794		const listEles = this.$unitList.querySelectorAll('.unit-list__item')
795		if (moreEle) {
796			moreEle.addEventListener('click', () => {
797				moreEle.classList.add('d-none')
798				listEles.forEach(val => {
799					val.classList.remove('hide-more-box')
800				})
801			})
802		}
803	}
804	initModal() {
805		this.modal = new Modal()
806		const $modal = this.$unit.querySelector('.inquiry-modal-inner')
807		if (!$modal) return
808		this.modal.init({
809			body: $modal,
810			title: window.app.utilts.$t('Free Quote & Information Request'),
811			size: 'lg',
812			className: 'inquiry-modal',
813			onSubmit: () => {
814				$modal.querySelector(`.btn`).click()
815			}
816		})
817	}
818	initInquiry() {
819		let inquiryBtn = this.$unit.querySelectorAll(".unit-list__product.no-price")
820		if (this.config.show_inquiry == 1 && inquiryBtn.length) {
821			this.initModal()
822			Array.from(inquiryBtn).forEach(_val => {
823				_val.querySelector('.unit-list__inquire').addEventListener('click', (e) => {
824					e.preventDefault()
825					e.stopPropagation()
826					this.modal.open()
827				})
828			})
829		}
830	}
831	initQuoteList() {
832		let quoteDiv = this.$unit.querySelectorAll(".unit-list__quote")
833		if (this.config.show_quote_list == 1 && quoteDiv.length) {
834			const productQuoteIdList = window.app.info.productQuoteIdList
835			Array.from(quoteDiv).forEach(_val => {
836				const contentId = _val.getAttribute("content-id")
837				const addBtn = _val.querySelector('.unit-list__quoteAdd')
838				const listBtn = _val.querySelector('.unit-list__quoteList')
839				if (productQuoteIdList.includes(contentId)) {
840					addBtn.style.display = 'none'
841					listBtn.style.display = 'inline-block'
842				}
843				_val.querySelector('.unit-list__quoteAdd').addEventListener('click', (e) => {
844					e.preventDefault()
845					e.stopPropagation()
846					if (this.info.productQuoteIdList.length >= 50) {
847						new Message().warn(window.app.utilts.$t('The number of added products has reached the maximum limit (50). '))
848						return
849					}
850					addBtn.style.display = 'none'
851					listBtn.style.display = 'inline-block'
852					const contentId = _val.getAttribute("content-id")
853					this.info.addProductQuoteId(contentId)
854				})
855			})
856		}
857	}
858
859	/**
860	 * 产品属性搜索客户渲染
861	 */
862	renderList(keyword='') {
863		this.content_type_list.forEach(item => {
864			if (item === 'page_content') {
865				this.pageInfo.page_number = window.app.info.pagination.page_number || 1
866			}
867			this.initLoadData(item,keyword)
868		})
869	}
870
871	/** 初始化选项卡切换事件 */
872	initTabEvent() {
873		if (this.$tabList.length === 0) return
874		this.$tabList.forEach($tab => {
875			$tab.addEventListener('click', () => {
876				// 当前选项卡选中
877				this.$tabList.forEach(p => p.classList.remove('active'))
878				$tab.classList.add('active')
879				// 当前内容选中
880				const tabtype = $tab.dataset.tabtype
881				// 产品选项卡内容dom
882				const $tabTypeItem = this.$unit.querySelectorAll('[tab-type]')
883				$tabTypeItem.forEach($tabContent => {
884					const selected = $tabContent.getAttribute('tab-type') === tabtype
885					if (selected) {
886						$tabContent.classList.remove('d-none')
887					} else {
888						$tabContent.classList.add('d-none')
889					}
890				})
891			})
892		})
893	}
894
895	async initLoadData(type = '',keyword='') {
896		if (type === 'products-discount-now') type = 'now'
897		else if (type === 'products-discount-upcoming') type = 'upcoming'
898
899		const validType = ['now', 'upcoming', 'page_content']
900		if (type && validType.includes(type) && (type !== 'page_content' || window.app.info.page.page_type === 'product_list')) {
901			const num = this.pageInfo.page_number
902			const size = this.pageInfo.page_size
903			const data = await window.app.getProductListPageBySearch(type, num, size,keyword)
904			let tabType = type
905			// if (tabType === 'youMightLike') tabType = 'you might like'
906			// else if (tabType === 'products-similar') tabType = 'similar'
907			const $nodeList = this.$unitList.querySelector('[tab-type="' + tabType + '"]')
908			this.getTabList($nodeList || this.$unitList, data.list)
909      // this.initVideoData($nodeList || this.$unitList)
910		}
911	}
912	getTabList($tabNode, list) {
913		const self = this
914		$tabNode.innerHTML = ''
915		if (list.length === 0 && this.$noData) {
916			this.$noData.classList.remove('d-none')
917			return
918		}
919		this.$noData.classList.add('d-none')
920		const params = {
921			open_hover: this.open_hover,
922			attrId: this.attrId, pageInfo: this.pageInfo, colInfo: this.colInfo, config: this.config
923		}
924		this.element = new ScriptContentListElement(params)
925		for (let index = 0; index < list.length; index++) {
926			const item = list[index];
927			const $itemNode = this.element.getItem(item)
928			if (item.video_gif) {
929				$itemNode.querySelector('.unit-list__img')?.setAttribute('hover-img', true)
930				$itemNode.querySelector('.unit-list__img')?.setAttribute('video-gif', item.video_gif)
931			}
932			this.element.$items.append($itemNode)
933		}
934		$tabNode.append(this.element.$container)
935		if (this.config.swiper.is_swiper) {
936			$tabNode.setAttribute('data-carousel', 0)
937		}
938		window.addEventListener('hookInitContentRender', function () {
939			self.initHoverImg()
940		}, {
941			once: false
942		})
943		window.app.initPlug(this.attrId, true)
944		this.initQuoteList()
945	}
946
947	initHoverContent() {
948
949	}
950
951	initHoverImg() {
952		const that = this
953		const hoverImgEffect = (this.open_hover || '').replace(/[^A-Za-z0-9,_-]/g, '').split(',')
954		const hoverImgIn = hoverImgEffect[0] || ''
955		const hoverImgOut = hoverImgEffect[1] || ''
956		const hoverImgDuration = hoverImgEffect[2] || ''
957		const doms = this.$unit.querySelectorAll('.unit-list__image[hover-img="true"]')
958		if (doms.length) {
959			doms.forEach((item, index) => {
960				let h_dom = item.querySelector('.unit-list-hover__image')
961				const video_gif = item.getAttribute('video-gif')
962				// if (!h_dom) return
963				let h_img = item.querySelector('.unit-list-hover__image img')
964				const hoverNextImg = h_img && h_img.src
965				let e_in = video_gif ? '' : hoverImgIn ? `animate__${hoverImgIn}` : ''
966				let e_out = video_gif ? '' : hoverImgOut ? `animate__${hoverImgOut}` : ''
967				const style_val = window.getComputedStyle(item)
968				const pt = style_val['paddingTop'] || '0px'
969				const pb = style_val['paddingBottom'] || '0px'
970				const pl = style_val['paddingLeft'] || '0px'
971				const pr = style_val['paddingRight'] || '0px'
972				if (`${pt + pb + pl + pr}` !== '0px0px0px0px' && h_dom) {
973					h_dom.setAttribute('style', `top:${pt};left:${pl};width:calc(100% - ${pl} - ${pr});height:calc(100% - ${pt} - ${pb});`)
974				}
975				let originImg = item.children[0].querySelector('.base-image__item') || item.querySelector('.unit-list__img .base-image__item') // hover原图的效果
976				if (hoverImgDuration) {
977					originImg.classList.add(hoverImgDuration)
978				}
979				h_dom && h_dom.classList.add('hover_img_before_load');
980				item.parentNode.onmouseover = e => {
981					let h_img = item.querySelector('.unit-list-hover__image img')
982					const hoverNextImg = h_img && h_img.src
983					if (h_dom && h_dom.classList.contains('hover_img_before_load')) {
984						h_dom.classList.remove('hover_img_before_load')
985					}
986					if (hoverNextImg) {
987						if (e_in) {
988							originImg.classList.remove(e_in)
989							h_dom.classList.add(e_in, 'animate__animated')
990						}
991						if (e_out) {
992							originImg.classList.add(e_out, 'animate__animated')
993							h_dom.classList.remove(e_out)
994						} else {
995							originImg.classList.add('opacity0')
996						}
997					} else {
998						if (e_in) {
999							originImg.classList.add(e_in, 'animate__animated')
1000						}
1001						if (e_out) {
1002							originImg.classList.remove(e_out)
1003						}
1004					}
1005					if (item.getAttribute('video-gif')) {
1006						originImg.classList.add('opacity0')
1007						// h_img.setAttribute('src', video_gif)
1008						item.querySelector('.base-video__play')?.classList.add('opacity0')
1009					}
1010				}
1011
1012
1013				item.parentNode.onmouseout = e => {
1014					originImg.classList.remove('opacity0')
1015					let h_img = item.querySelector('.unit-list-hover__image img')
1016					const hoverNextImg = h_img && h_img.src
1017					if (hoverNextImg) {
1018						if (e_in) {
1019							originImg.classList.add(e_in, 'animate__animated')
1020							h_dom.classList.remove(e_in)
1021						}
1022						if (e_out) {
1023							originImg.classList.remove(e_out)
1024							h_dom.classList.add(e_out, 'animate__animated')
1025						} else {
1026							if (h_dom) {
1027								h_dom.classList.add('hover_img_before_load')
1028							}
1029						}
1030					} else {
1031						if (e_in) {
1032							originImg.classList.remove(e_in)
1033						}
1034						// if (e_out) {
1035						// 	originImg.classList.add(e_out, 'animate__animated')
1036						// }
1037					}
1038					if (item.getAttribute('video-gif')) {
1039						// h_img.setAttribute('src', '')
1040						item.querySelector('.base-video__play')?.classList.remove('opacity0')
1041					}
1042				}
1043			})
1044		}
1045	}
1046	initVideo() {
1047		const doms = this.$unit.querySelectorAll('[video-src]')
1048		if (!doms.length) {
1049			return
1050		}
1051    const slideNext = () => {
1052      const swiper = this.$carouselEl.swiper
1053      if (swiper && swiper.slideNext) {
1054        swiper.slideNext()
1055      }
1056    }
1057		const config = this.config.video
1058		doms.forEach(($el, index) => {
1059			let url = $el.getAttribute('video-src')
1060			const videothumbDom = $el.querySelector('.base-video__thumb img')
1061			const videothumb = videothumbDom.getAttribute('src') || videothumbDom.getAttribute('lazy-src')
1062			const isIframe = /^\s*<iframe[^>]*>[\s\S]*?<\/iframe>\s*$/.test(url)
1063			const isMp4 = /\.(mp4|m3u8)(\?|$)/i.test(url || '')
1064			const showMask = config.show_mask * 1
1065			const opacity = showMask?`filter:brightness(${config.opacity});`:''
1066      const showControls = config.controls && config.controls.toString() === '1' || false
1067      if (url) {
1068        // 重播
1069        const replayWrap =
1070          `<div class="base-video__wrap--replay">
1071          <div class="replay-icon">
1072            <svg height="100%" version="1.1" viewBox="0 0 36 36" width="100%">
1073              <path class="ytp-svg-fill" d="M 18,11 V 7 l -5,5 5,5 v -4 c 3.3,0 6,2.7 6,6 0,3.3 -2.7,6 -6,6 -3.3,0 -6,-2.7 -6,-6 h -2 c 0,4.4 3.6,8 8,8 4.4,0 8,-3.6 8,-8 0,-4.4 -3.6,-8 -8,-8 z" id="ytp-id-125"></path>
1074            </svg>
1075          </div>
1076        </div>`
1077				const videoList = [
1078					`<div class="base-video__wrap">
1079            ${showControls && this.method=== '2' ? '<div class="base-video__wrap--close">×</div>': ''}
1080            ${showControls && this.method=== '2' ? replayWrap : replayWrap}
1081            <video
1082              style="height:auto;display:block;margin:0 auto;max-width:100%;${opacity}"
1083              autoplay
1084              controlsList="nodownload"
1085              webkit-playsinline="true"
1086              playsinline="true"
1087              x5-video-player-type="h5-page"
1088              preload="metadata"
1089              src="${url}"
1090              ${config.loop && config.loop.toString() === '1' ? ' loop' : ''}
1091              ${config.muted && config.muted.toString() === '1' ? ' muted' : ''}
1092              ${showControls ? ' controls' : '' }
1093              poster="${videothumb}"
1094            ></video>
1095          </div>`,
1096					'<iframe '+ opacity +' width="100%" frameborder="0" allow="autoplay" allowfullscreen="true" webkitallowfullscreen="true" mozallowfullscreen="true" src="' + url + '"></iframe>'
1097				]
1098
1099        let videoHtml;
1100        let iframeUrl = []
1101        if (isIframe) {
1102          iframeUrl = globalThis.Server.iframeAutoplay(url).split('<iframe')
1103          videoHtml = `<iframe style="filter:brightness(${showMask?config.opacity:'1'})"`+iframeUrl[1]
1104        } else if (isMp4) {
1105          // videoHtml = videoList[0]
1106          if (this.utilts.getDevice().access_device === 'PC') { // 没鼠标不需要播放,通过this.initLink()绑定事件直接跳转详情页
1107            const videoPlayer = new VideoPlayer($el.querySelector('.video-container'), url, {
1108              trigger: 'hover',
1109              ...config,
1110              playerConfig: {
1111                poster: videothumb,
1112              }
1113            })
1114            const swiperAutoplay = parseInt(this.config.swiper.autoplay || '0')
1115            if (swiperAutoplay) {
1116              videoPlayer.on('play', () => {
1117                if (this.$carouselEl.swiper) {
1118                  this.$carouselEl.swiper.autoplay.stop()
1119                }
1120              })
1121              videoPlayer.on('destroy', () => {
1122                if (this.$carouselEl.swiper) {
1123                  this.$carouselEl.swiper.autoplay.start()
1124                }
1125              })
1126            }
1127          }
1128          return
1129        } else {
1130          videoHtml = globalThis.Server.iframeAutoplay(videoList[1])
1131        }
1132        const stopPlay = (e) => {
1133          // 判断在选择隐藏文本与不轮播情况下不显示文本
1134          if (!swiperContainerEle.swiper && config.auto_hide == 1) {
1135            // swiperContainerEle.querySelector('.unit-list__text').style.opacity = 0
1136            $el.closest('.unit-list__item').classList.add('hide-videotext')
1137          }
1138          if (!swiperContainerEle.swiper) return
1139          if (swiperContainerEle) swiperContainerEle.swiper.autoplay.stop()
1140          // 轮播模式下是否自动隐藏文本的判断,上面是非轮播模式,不冲突
1141          if (parseInt(config.auto_hide) === 1) {
1142            // swiperContainerEle.swiper.slides[swiperContainerEle.swiper.activeIndex].querySelector('.unit-list__text').style.opacity = 0
1143            $el.closest('.unit-list__item').classList.add('hide-videotext')
1144          }
1145          // 调用play()方法进行自动播放
1146          // swiperContainerEle.getElementsByTagName("video")[0].play()
1147          e.target.play()
1148        }
1149        const startPlay = (e) => {
1150          if (!swiperContainerEle.swiper && config.auto_hide == 1) {
1151            // swiperContainerEle.querySelector('.unit-list__text').style.opacity = 1
1152            $el.closest('.unit-list__item').classList.remove('hide-videotext')
1153          }
1154          if (!swiperContainerEle.swiper) return
1155          // 如果配置不需要自动轮播,则不再恢复自动轮播
1156          if (swiperContainerEle && this.config.swiper.autoplay !== '0') swiperContainerEle.swiper.autoplay.start()
1157          if (parseInt(config.auto_hide) === 1) {
1158            // swiperContainerEle.swiper.slides[swiperContainerEle.swiper.activeIndex].querySelector('.unit-list__text').style.opacity = 1
1159            $el.closest('.unit-list__item').classList.remove('hide-videotext')
1160          }
1161        }
1162        const resetVideo = $el.resetVideo = () => {
1163          const $preview = $el.querySelector('.base-video__preview')
1164          const $video = $el.querySelector('.base-video__preview video')
1165          const $replayWrap = $el.querySelector('.base-video__preview').querySelector('.base-video__wrap--replay')
1166          if ($preview) {
1167            const videoWrapDom = $preview.querySelector('.base-video__wrap')
1168            // console.log('videoWrapDom', videoWrapDom)
1169
1170            const isSwiper = this.config.swiper.is_swiper
1171            // console.log('isSwiper', isSwiper)
1172            if (!this.config.swiper.is_swiper) {
1173              // console.log('不是 swiper')
1174              $replayWrap.style.display = 'flex'
1175              $video.controls = false
1176              return
1177            }
1178            if (videoWrapDom) {
1179              videoWrapDom.remove()
1180            }
1181            $preview.querySelectorAll('video, iframe').forEach(video => {
1182              if (video instanceof HTMLVideoElement) {
1183                video.removeEventListener("ended", resetVideo)
1184              }
1185              video.remove()
1186            })
1187            $preview.classList.remove('play')
1188          }
1189        }
1190        // 当前播放
1191        const playVideo = $el.playVideo = () => {
1192          const videothumb = $el.querySelector('.base-video__thumb img')
1193          const videotDom = $el.querySelector('.base-video__preview video')
1194          const videoPoster = videothumb && (videothumb.currentSrc || videothumb.getAttribute('src') || videothumb.getAttribute('lazy-src'))
1195          const $preview = $el.querySelector('.base-video__preview')
1196          const $videos = $preview.querySelectorAll('video, iframe')
1197          $preview.classList.add('play')
1198          // $el.getAttribute('videoscale') && $el.classList.add('base-video--scale')
1199          $el.classList.add('play')
1200          if ($preview && !$videos.length) {
1201            const template = document.createElement('template')
1202            template.innerHTML = videoHtml
1203            const videos = Array.from(template.content.children)
1204            videos.forEach(video => {
1205              $preview.insertAdjacentElement('beforeend', video)
1206            })
1207          }
1208          if (this.$carouselEl.swiper) {
1209            this.$carouselEl.swiper.autoplay.stop()
1210          }
1211          if (videothumb && videotDom) videotDom.poster = videothumb.getAttribute('src') || videothumb.getAttribute('lazy-src')
1212          $el.querySelector('.base-video__preview').classList.add('play')
1213          // $el.getAttribute('videoscale') && $el.classList.add('base-video--scale')
1214          $el.classList.add('play')
1215          const closeBtn = $el.querySelector('.base-video__preview').querySelector('.base-video__wrap--close')
1216          const replayBtn = $el.querySelector('.base-video__preview').querySelector('.replay-icon')
1217          if (showControls && closeBtn) {
1218            const closeVideo = (event) => {
1219              event.stopPropagation()
1220              event.preventDefault()
1221              const videoWrapDom =  $el.querySelector('.base-video__preview').querySelector('.base-video__wrap')
1222              if (videoWrapDom) {
1223                videoWrapDom?.remove()
1224                $el.querySelector('.base-video__preview')?.classList.remove('play')
1225                $el.classList.remove('play')
1226              }
1227            }
1228            closeBtn.addEventListener('click', closeVideo, { once: true })
1229          }
1230          // console.log('auto_reset', this.config.video.auto_reset)
1231          // if (showControls && replayBtn && this.config.video.auto_reset !== '1') {
1232          if (showControls && replayBtn ) {
1233            const videoDom = $el.querySelector('.base-video__wrap video')
1234            const replayWrapDom = $el.querySelector('.base-video__preview').querySelector('.base-video__wrap--replay')
1235            // console.log('videoDom', videoDom)
1236            const showReplayBtn = (event) => {
1237              event.stopPropagation()
1238              event.preventDefault()
1239              if(replayWrapDom) {
1240                replayWrapDom.style.display = 'flex'
1241                videoDom.controls = false
1242              }
1243            }
1244            videoDom?.addEventListener('ended', showReplayBtn)
1245            const replay = (event) => {
1246              event.stopPropagation()
1247              event.preventDefault()
1248              videoDom.currentTime = 0
1249              videoDom.play()
1250              replayWrapDom.style.display = 'none'
1251              videoDom.controls = true
1252            }
1253            replayBtn?.addEventListener('click', replay)
1254          }
1255          // console.log('auto_reset', this.config.video.auto_reset)
1256          // console.log('config', this.config)
1257          let myVideo = $el.querySelectorAll('video')
1258          const swiperAutoplay = parseInt(this.config.swiper.autoplay || '0')
1259          myVideo.forEach(elVideo => {
1260            if (videoPoster) {
1261              elVideo.poster = videoPoster
1262            }
1263            elVideo.removeEventListener('play', stopPlay)
1264            elVideo.addEventListener('play', stopPlay)
1265            elVideo.removeEventListener('pause', startPlay)
1266            elVideo.addEventListener('pause', startPlay)
1267            if (this.config.video.auto_reset > 0) {
1268              elVideo.removeEventListener("ended", resetVideo);
1269              if (swiperAutoplay === 0) {
1270                // 自动轮播的情况下,视频播放结束不自动重置
1271                elVideo.addEventListener("ended", resetVideo, {once: true});
1272              }
1273            }
1274            if (swiperAutoplay > 0 && !elVideo._eventSlideNext) {
1275              elVideo._eventSlideNext = slideNext
1276              elVideo.addEventListener("ended", slideNext, {once: true});
1277            }
1278          })
1279          // if (myVideo) {
1280          // 	myVideo.removeEventListener('play', stopPlay)
1281          // 	myVideo.addEventListener('play', stopPlay)
1282          // 	myVideo.removeEventListener('pause', startPlay)
1283          // 	myVideo.addEventListener('pause', startPlay)
1284          // 	if (this.config.video.auto_reset > 0) {
1285          // 		myVideo.removeEventListener("ended", resetVideo);
1286          // 		myVideo.addEventListener("ended", resetVideo);
1287          // 	}
1288          // }
1289        }
1290        const clickPlayVideo = (e) => {
1291          e.stopPropagation()
1292          e.stopImmediatePropagation()
1293          if (!$el.querySelector('.base-video__preview').classList.contains('play')) {
1294            // 有视频
1295            // e.preventDefault()
1296            playVideo()
1297          }
1298
1299          // if (/\.mp4(\?|$)/.test(url) && window.app.utilts.checkScreenMobile()) {
1300          // 	// 手机端
1301          // 	$el.querySelector('video').requestFullscreen()
1302          // }
1303          return false
1304        }
1305        if (config.autoplay.toString() === '1' && isMp4 && $el.querySelector('.base-video__preview').classList.value.indexOf('play') === -1) {
1306          // 自动播放
1307          playVideo()
1308          if (this.config.video.auto_reset > 0) {
1309            $el.addEventListener('click', clickPlayVideo, {useCapture: false})
1310          }
1311        } else {
1312          // 手动播放
1313          if (isIframe) {
1314            videoHtml = this.config.default_src ? videoHtml : globalThis.Server.iframeAutoplayClear(videoHtml, config.muted && config.muted.toString() === '1')
1315          }
1316          $el.addEventListener('click', clickPlayVideo, {useCapture: false})
1317        }
1318			}
1319		})
1320	}
1321
1322	initResize() {
1323		if (!this.config.resize?.is_resize) return
1324
1325		const $container = this.$unitList.querySelector('.resize-container')
1326		if (!$container) return
1327		const $wrapper = $container.querySelector('.unit-list__items')
1328		const $firstItem = $wrapper.firstElementChild
1329		const $firstItemInner = $firstItem.querySelector('.unit-list__item-inner')
1330		const $laseItem = $wrapper.lastElementChild
1331		// const $firstImg = $firstItem.querySelector('.base-image__img')
1332		// const $firstText = $firstItem.querySelector('.unit-list__text')
1333		const $splitLine = $container.querySelector('.unit-list__split-line')
1334
1335		let direction = this.config.resize?.direction || 'x';
1336		let offsetX = 0;
1337		let offsetY = 0;
1338
1339		// $firstText.setAttribute('style', `width:${$container.offsetWidth * 0.5}px;`)
1340		if (direction === 'x') {
1341			$firstItemInner.setAttribute('style', `width:${$container.offsetWidth}px;max-width:${$container.offsetWidth}px`)
1342			// 监听 container 尺寸变化
1343			var observer = new ResizeObserver(function (entries) {
1344				entries.forEach(function (entry) {
1345					if (entry.target === $container) {
1346						// 获取宽度
1347						const width = entry.contentRect.width;
1348						$firstItemInner.setAttribute('style', `width:${width}px;max-width:${width}px`)
1349					}
1350				});
1351			});
1352			// 监听目标元素的宽度变化
1353			observer.observe($container);
1354		}
1355
1356		function startDrag(event) {
1357			event.preventDefault()
1358
1359			offsetX = $container.getBoundingClientRect().left;
1360			offsetY = $container.getBoundingClientRect().top;
1361			document.addEventListener('mouseup', stopDrag)
1362			document.addEventListener('mousemove', drag)
1363
1364			document.addEventListener('touchend', stopDrag)
1365			document.addEventListener('touchmove', drag, {
1366				passive: false, // 阻止默认滚动行为
1367			})
1368		}
1369
1370		function stopDrag(event) {
1371			event.preventDefault()
1372
1373			document.removeEventListener('mousemove', drag)
1374			document.removeEventListener('mouseup', stopDrag)
1375
1376			document.removeEventListener('touchmove', drag)
1377			document.removeEventListener('touchend', stopDrag)
1378		}
1379
1380		function drag(event) {
1381			event.preventDefault()
1382			requestAnimationFrame(() => {
1383				if (direction === 'x') {
1384					let containerLeft = $container.getBoundingClientRect().left;
1385					let containerWidth = $container.offsetWidth;
1386					let clientX = 'touches' in event ? event.touches[0].clientX : event.clientX
1387					let x = clientX - offsetX;
1388					// 将拖拽区域限制在容器内部
1389					if (clientX < containerLeft) {
1390						// console.log('左边超出');
1391						x = 0;
1392					}
1393					if (clientX > containerLeft + containerWidth - $splitLine.offsetWidth) {
1394						// console.log('右边超出');
1395						x = containerWidth - $splitLine.offsetWidth
1396					}
1397					$splitLine.style.left = x + "px";
1398					$firstItem.setAttribute('style', `width:${x}px`)
1399					$laseItem.setAttribute('style', `clip-path: inset(0 0 0 ${x}px)`) // fix:透明背景,图片重叠
1400				} else {
1401					let containerTop = $container.getBoundingClientRect().top
1402					let containerHeight = $container.offsetHeight;
1403					let clientY = 'touches' in event ? event.touches[0].clientY : event.clientY
1404					let y = clientY - offsetY;
1405					// 将拖拽区域限制在容器内部
1406					if (clientY < containerTop) {
1407						y = 0;
1408					}
1409					if (clientY > containerTop + containerHeight - $splitLine.offsetHeight) {
1410						y = containerHeight - $splitLine.offsetHeight;
1411					}
1412					$splitLine.style.top = y + "px";
1413					$firstItem.setAttribute('style', `height:${y}px`)
1414					$laseItem.setAttribute('style', `clip-path: inset(${y}px 0 0 0)`)
1415				}
1416			})
1417		}
1418
1419		$splitLine.onmousedown = startDrag;
1420		$splitLine.ontouchstart = startDrag;
1421	}
1422
1423	initLink() {
1424		// 点击卡片跳转详情
1425		const $listAList = this.$unitList.querySelectorAll('.unit-list__a[data-href]')
1426
1427		for (const item of $listAList) {
1428			const dataHref = item.getAttribute('data-href')
1429      if (!this.utilts.checkDesign()) {
1430				if (dataHref.startsWith('javascript')) continue
1431				item.style.cursor = 'pointer'
1432				item.addEventListener('click', (e) => {
1433          if (e.target.closest('.xgplayer-controls')) return
1434
1435					const link = e.target.closest('a[href]');
1436					if (link && link.href && !link.href.startsWith('javascript')) {
1437						e.stopPropagation();
1438						return false;
1439					}
1440
1441					let target = item.getAttribute('data-target')
1442					if (target !== 'block') {
1443						window.open(dataHref, target || '_self')
1444					}
1445				}, true)
1446			}
1447		}
1448	}
1449}
1450
1451/**
1452 * 客户端数据html
1453 */
1454class ScriptContentListElement {
1455	constructor({ attrId, pageInfo, colInfo, config, open_hover }) {
1456		this.open_hover = open_hover
1457		this.attrId = attrId
1458		this.pageInfo = pageInfo
1459		this.is_swiper = config.swiper.is_swiper
1460		this.colInfo = colInfo
1461		this.config = config
1462		this.init()
1463	}
1464
1465	init() {
1466		this.getMainHtml()
1467	}
1468
1469	getMainHtml() {
1470		this.$container = document.createElement('div')
1471		this.$container.classList.add('swiper-container')
1472		this.$items = this.getItems()
1473		this.$container.append(this.$items)
1474		this._setSwiperNode()
1475	}
1476
1477	getItems() {
1478		const $items = document.createElement('div')
1479		$items.classList.add('unit-list__items', 'swiper-wrapper')
1480		if (!this.is_swiper) $items.classList.add('row')
1481		if (this.is_swiper && !this.swiper.pagination) $items.classList.add('no-swiper-pagination')
1482		return $items
1483	}
1484
1485	/** 获取产品列表项 **/
1486	getItem(item) {
1487		const $item = document.createElement('div')
1488		$item.setAttribute('data-id', item.content_id)
1489		$item.classList.add('animate', 'unit-list__item', 'swiper-slide')
1490		if (!this.is_swiper) {
1491			$item.classList.add(`col-${this.colInfo.cols_col}`)
1492			$item.classList.add(`col-md-${this.colInfo.cols_md}`)
1493			$item.classList.add(`col-xl-${this.colInfo.cols_xl}`)
1494		}
1495		const $listA = document.createElement('div')
1496		$listA.classList.add('unit-list__a')
1497		$listA.append(this.getItemContent(item))
1498		$item.append($listA)
1499
1500		return $item
1501	}
1502	/** 获取产品列表项内容 **/
1503	getItemContent(item) {
1504		const $listInner = document.createElement('div')
1505		$listInner.classList.add('unit-list__item-inner', 'd-flex', 'flex-column')
1506		$listInner.append(this.getLinkImage(item))
1507		$listInner.append(this.getLinkText(item))
1508		return $listInner
1509	}
1510
1511	/**
1512	 * 按钮节点
1513	 */
1514	getLinkImage(item) {
1515		const hoverImgEffect = (this.open_hover || '').replace(/[^A-Za-z0-9,_-]/g, '').split(',')
1516		const hoverImgIn = hoverImgEffect[0] || ''
1517		const hoverImgOut = hoverImgEffect[1] || ''
1518		const hoverImgDuration = hoverImgEffect[2] || ''
1519		const self = this
1520		const subNode = {
1521			//
1522			get baseImage() {
1523				let scale = ''
1524				let effect = 0
1525				if (self.config.image) {
1526					scale = self.config.image.scale || ''
1527					if (scale) scale = Number(scale) * 100 + '%'
1528					effect = self.config.image.effect
1529				}
1530				return `
1531					<div class="base-image ${scale ? 'base-image--scale' : ''} ${effect ? 'base-image--effect-' + effect : ''}" ${scale ? 'style="--img-pt: ' + scale + '"' : ''}>
1532						<div class="base-image__item hover_img_origin base-image__item--default">
1533							<img class="base-image__img img-fluid ${hoverImgDuration}" effect-in="${hoverImgIn}" effect-out="${hoverImgOut}" lazy-src="${item.img}" alt="${item.alt || item.title}" lazy-type="img">
1534						</div>
1535					</div>`
1536			},
1537		}
1538
1539		const $imgBoxs = document.createElement('a')
1540		$imgBoxs.classList.add('unit-list__image')
1541		const href = globalThis.Server.getRinseHref(item.href || 'javascript:;', window.app.info.site)
1542		$imgBoxs.setAttribute('href', href)
1543		$imgBoxs.setAttribute('target', item.target || '_self')
1544
1545		if (item.cover_url && this.config.video.icon === '1') {
1546			const videoNode = document.createElement('div')
1547			videoNode.classList.add('base-video__play')
1548			videoNode.innerHTML = `<i class="iconfont icon-action-play"></i>`
1549			$imgBoxs.appendChild(videoNode)
1550		}
1551
1552		// 产品图片
1553		const $baseImg = document.createElement('div')
1554		// console.log('item*---list', item);
1555		$baseImg.classList.add('unit-list__img')
1556		$baseImg.setAttribute('content-render', 'product_hover,video_icon')
1557		$baseImg.setAttribute('content-type', item.content_type)
1558		$baseImg.setAttribute('content-id', item.content_id);
1559		(item.hover_img || self.config.hover_img) && $baseImg.setAttribute('open-hover', this.open_hover || '')
1560		$baseImg.innerHTML = subNode.baseImage
1561		$imgBoxs.append($baseImg)
1562		return $imgBoxs
1563	}
1564
1565	/**
1566	 * 标题描述,价格
1567	 */
1568	getLinkText(item) {
1569		const self = this
1570		const getShowContent = (className, item, textStyle, title) => {
1571			const $titleBox = document.createElement('div')
1572			$titleBox.classList.add(`unit-list__${className}`)
1573			$titleBox.setAttribute('text-style', textStyle || '')
1574
1575			let $textBox
1576			if (className === 'title') {
1577				$textBox = document.createElement('a')
1578				const href = globalThis.Server.getRinseHref(item.href || 'javascript:;', window.app.info.site)
1579				$textBox.setAttribute('href', href)
1580				$textBox.setAttribute('target', item.target || '_self')
1581			} else {
1582				$textBox = document.createElement('div')
1583			}
1584			$textBox.classList.add('text_ellipsis')
1585			$textBox.setAttribute('_html', item[className + '_sign'] || '')
1586			$textBox.setAttribute('toolbar', 'false')
1587			$textBox.innerHTML = item[className]
1588			$titleBox.append($textBox)
1589
1590			return $titleBox
1591		}
1592		const subNode = {
1593			get priceInfo() {
1594				const min = `<div class="unit-list__price-min"><i>$</i><span>${item.price_min}</span></div>`
1595				let max = ''
1596				if (item.price_max > 0) {
1597					max = `<div class="unit-list__price-max"><i>$</i><span>${item.price_max}</span></div>`
1598				}
1599				return `${min}${max}`
1600			},
1601			get listExtend() {
1602				const noPrice = `
1603						<div class="unit-list__cart text-capitalize">
1604							<i class="iconfont icon-base-cart-lighter"></i>
1605							<a href="${globalThis.Server.getRinseHref(item.href, window.app.info.site)}" target="${item.target || '_self'}">${window.app.utilts.$t('Add to cart')}
1605 </a>
1606						</div>
1607						<div class="unit-list__inquire text-capitalize">
1608							<a href="${item.target==='block'?'javascript:;':globalThis.Server.getRinseHref(item.href, window.app.info.site)}" target="${item.target==='block'?'_self':item.target || '_self'}">${window.app.utilts.$t('Inquiry')}</a>
1609						</div>`
1610				let like = ''
1611				if (self.config.show_like) {
1612					like = `
1613						<div class="unit-list__like" title="${window.app.utilts.$t('Like')}" pro-id="${item.id}">
1614								<i class="iconfont icon-base-collect"></i>
1615						</div>`
1616				}
1617				return `${noPrice}${like}`
1618			}
1619		}
1620
1621		const $textBox = document.createElement('div')
1622		$textBox.classList.add('unit-list__text')
1623
1624		const $textInner = document.createElement('div')
1625		$textInner.classList.add('unit-list__text-inner')
1626
1627		const $content = document.createElement('div')
1628		$content.classList.add('unit-list__content')
1629
1630		$textInner.append($content)
1631		$textBox.append($textInner)
1632
1633		// 标题
1634		if (this.config.show_title && item.title && this.config.has_title) {
1635			const style_title = self.config.style_type_title
1636			const $title = getShowContent('title', item, style_title)
1637			$content.append($title)
1638		}
1639		// 子标题
1640		if (this.config.show_subtitle && item.subtitle && this.config.has_subtitle) {
1641			const style_subtitle = self.config.style_type_subtitle
1642			const $subtitle = getShowContent('subtitle', item, style_subtitle)
1643			$content.append($subtitle)
1644		}
1645		// 描述
1646		if (this.config.show_description && item.description && this.config.has_description) {
1647			const style_description = self.config.style_type_description
1648			const $description = getShowContent('description', item, style_description)
1649			$content.append($description)
1650		}
1651
1652		// ä»·æ ¼
1653		if (this.config.show_read_more) {
1654			const $pricesBox = document.createElement('div')
1655			$pricesBox.classList.add('unit-list__product')
1656			if (Number(item.price_min) <= 0) $pricesBox.classList.add('no-price')
1657
1658			const $listPrice = document.createElement('div')
1659			$listPrice.classList.add('unit-list__price')
1660			$listPrice.innerHTML = subNode.priceInfo
1661			$pricesBox.append($listPrice)
1662
1663			const $extend = document.createElement('div')
1664			$extend.classList.add('unit-list__extend')
1665			$extend.innerHTML = subNode.listExtend
1666			$pricesBox.append($extend)
1667
1668			$textInner.append($pricesBox)
1669		}
1670		if (this.config.show_quote_list == '1') {
1671			$textBox.append(this.getQuoteBtn(item))
1672		}
1673		return $textBox
1674	}
1675
1676	getQuoteBtn(item) {
1677		const self = this
1678		const $content = document.createElement('div')
1679		$content.classList.add('unit-list__quote')
1680		$content.setAttribute("content-id", item.content_id)
1681		const $addBtn = document.createElement('div')
1682		$addBtn.classList.add('unit-list__quoteAdd')
1683		$addBtn.innerHTML = `<i class="iconfont icon-action-add"></i>
1684                        <span>${window.app.utilts.$t('Add to Quote List')}</span>`
1685		const $listBtn = document.createElement('a')
1686		$listBtn.classList.add('unit-list__quoteList')
1687		$listBtn.innerHTML = ` <div>
1688                            ${window.app.utilts.$t('Browse the list')} →
1689                        </div>`
1690		$content.append($addBtn)
1691		$content.append($listBtn)
1692		return $content
1693	}
1694	/** **/
1695	_setSwiperNode() {
1696		if (this.config.swiper) {
1697			if (this.config.swiper.pagination) {
1698				const $div1 = document.createElement('div')
1699				$div1.classList.add('unit-product-list__pagination', 'swiper-pagination')
1700				this.$container.append($div1)
1701			}
1702			if (this.config.swiper.navigation) {
1703				const $div2 = document.createElement('div')
1704				$div2.classList.add('unit-product-list__button-prev', 'swiper-button-prev')
1705				this.$container.append($div2)
1706				const $div3 = document.createElement('div')
1707				$div3.classList.add('unit-product-list__button-next', 'swiper-button-next')
1708				this.$container.append($div3)
1709			}
1710			if (this.config.swiper.scrollbar) {
1711				const $div4 = document.createElement('div')
1712				$div4.classList.add('unit-product-list__scrollbar', 'swiper-scrollbar')
1713				this.$container.append($div4)
1714			}
1715		}
1716	}
1717}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.