PageSourceSearch

https://www.hasungmachinery.com/assets/js/unit/product-sort-m.js

js hasungmachinery.com collected 2026-10-04 06:54:36 UTC 18,159 bytes, 472 lines download raw bytes

1/**
2 * 产品排序组件
3 */
4class ScriptProductSortMobile extends Script {
5	constructor(params) {
6		super(params)
7		this.$unit = document.querySelector(`#${this.attrId}`)
8		if (!this.$unit) return
9		this.prefx = 'unit-product-sort-m'
10		this.$main = this.$unit.querySelector(`.${this.prefx}__items`)
11		if(this.$main) this.$main.innerHTML = ''
12		// 排序项
13		this.sortName = Utilts.ins().$t('Sort By')
14		this.$drop = this.$unit.querySelectorAll('.unit-header-menu__nav__item-drop')
15		this.templateType = params.templateType 
16		// 排序项
17		this.sortList = [
18			{ id: 5, name: Utilts.ins().$t('Default'), active: false, sort: 'sort desc,create_time desc' },
19			{ id: 1, name: Utilts.ins().$t('Newest'), active: false, sort: 'create_time desc,id desc' },
20			{ id: 2, name: Utilts.ins().$t('Lowest Price'), active: false, sort: 'price asc' },
21			{ id: 3, name: Utilts.ins().$t('Highest Price'), active: false, sort: 'price desc' },
22			{ id: 4, name: Utilts.ins().$t('Hot Sale'), active: false, sort: 'order desc' },
23			{ id: 5, name: Utilts.ins().$t('Most Popular'), active: false, sort: 'favorite desc' }
24		]
25		if(this.templateType==='b2b'){
26			this.sortList = [
27				{ id: 5, name: Utilts.ins().$t('Default'), active: false, sort: 'sort desc,create_time desc' },
28				{ id: 1, name: Utilts.ins().$t('Newest'), active: false, sort: 'create_time desc,id desc' },
29			]
30		}
31		this.$maintwo = this.$unit.querySelectorAll(`.unit-header-menu_right_slide_view .unit-attr-search__items`)
32		// this.$maintwo.innerHTML = ''
33		const that = this;
34		/**
35		 * 选中的checkbox
36		 * @type {{}}
37		 */
38		this.checkedAttrs = new Proxy({}, {
39		  set(target, p, value) {
40			if (value?.id && value?.product_attr_id) {
41				that.$maintwo.forEach(a=>{
42					var checkboxWrapNode = a.querySelector(`.unit-attr-search__content--checkbox[data-checkbox_uid="${value.product_attr_id}-${value.id}"]`)
43			  		checkboxWrapNode && (value.checked ? checkboxWrapNode.classList.add('is_active') : checkboxWrapNode.classList.remove('is_active'))
44				})
45			}
46			return Reflect.set(target, p, value);
47		  }
48		});
49		//搜索项
50		this.$mainthree = this.$unit.querySelector('.unit-attr-text-search-right_slide__items')
51		this.product_attr_id = ''
52		this.showSearchItemName = '--Please Selected--'
53	}
54	/** 下拉事件 */
55	initDropEvent() {
56		for (let $el of this.$drop) {
57			$el.addEventListener('click', (e) => {
58			e.stopPropagation()
59			e.preventDefault()
60			$el.classList.toggle('active')
61			const $content = $el.parentNode.parentNode.children[1] || null
62			if ($content) {
63				if(this.$droupDowm){
64					this.$droupDowm.classList.remove('show')
65				}
66				$content.classList.toggle('show')
67			}
68			})
69		}
70	}
71	async init() {
72		var that = this;
73		if(this.$maintwo){
74			this.initDropEvent()
75			this.initListeners();
76		}
77		if(this.$mainthree){
78			this.createdSearchElement()
79			this.initLoadData()
80			this.initEvent()
81		}
82		if(this.$main){
83			this.initSort()
84			this.initHideElement()
85			const sortItems = document.querySelector(`#${this.attrId} .unit-product-sort-m__items`)
86			const prefix = this.prefx
87			const unitElem = this.$unit
88			const sortList = this.sortList
89			sortItems.addEventListener('click', function (evt) {
90				const clickElem = evt.target
91				const elemFilterTextReg = new RegExp(`${prefix}__filter(-text)?\\b(?!-)`, 'i')
92				const elemFilterPosiText = new RegExp(`${prefix}__filter-posi(-text)?\\b(?!-)`, 'i')
93				if (elemFilterTextReg.test(clickElem.className) || elemFilterTextReg.test(clickElem.parentElement.className)) {
94					// 打开下拉排序列表
95					evt.stopPropagation()
96					const itemSearchFilterBox = unitElem.querySelector(`.${prefix}__filter-text`)
97					itemSearchFilterBox && itemSearchFilterBox.classList.toggle('is_active')
98				} else if (clickElem instanceof HTMLParagraphElement && elemFilterPosiText.test(clickElem.parentElement.className)) {
99					// 排序下拉列表选中元素点击
100					evt.stopPropagation()
101					const list = Array.prototype.filter.call(clickElem.parentElement.children, function (node) {
102						return node instanceof HTMLParagraphElement
103					})
104					const idx = list.indexOf(clickElem)
105					list.forEach(function (elem) {
106						elem === clickElem ? (elem.classList.add('is_active')) : (elem.classList.remove('is_active'))
107					})
108					if (idx > -1 && sortList[idx]) {
109						const filter = sortList[idx]
110						window.app.info.product_sort = filter.sort
111						if (window.app.info && window.app.info.renderListView) {
112							window.app.info.renderListView()
113						}
114					}
115					const itemSearchFilterBox = unitElem.querySelector(`.${prefix}__filter-text`)
116					itemSearchFilterBox.classList.toggle('is_active')
117					itemSearchFilterBox.firstChild.innerText = clickElem.innerText
118				}
119			})
120			document.querySelector('body').addEventListener('touchmove', () => {
121				const itemSearchFilterBox = unitElem.querySelector(`.${prefix}__filter-text`)
122				itemSearchFilterBox && itemSearchFilterBox.classList.remove('is_active')
123			})
124		}
125		var rightSlideView = document.querySelector(`.unit-header-menu_right_slide_view`);
126		var filterBtn = document.querySelector(`.unit-product-sort__filter_btn`)
127		if(filterBtn){
128			filterBtn.addEventListener('click', function (evt) {
129				console.log(document.getElementById('app'))
130				if(document.getElementById('app').querySelectorAll('.unit-header-menu_right_slide_view').length>0){
131					rightSlideView.remove()
132					document.getElementById('app').appendChild(rightSlideView)
133				}
134				rightSlideView.style.display = 'block'
135				document.body.style.overflow = 'hidden'
136			})
137			var rightSlideClose = document.querySelectorAll(`.unit-header_right_slide-close`)
138			rightSlideClose.forEach(a=>{
139				a.addEventListener('click', function (evt) {
140					rightSlideView.style.display = 'none'
141					document.body.style.overflow = 'auto'
142					setTimeout(()=>{
143						document.documentElement.scrollTop=0
144					},200)
145				})
146			})
147			var rightSlideDeselect = document.querySelector(`.unit-header_right_slide-deselect`)
148			rightSlideDeselect.addEventListener('click', function (evt) {
149				that.initListeners(true)
150				that.$input.value = ''
151				that.searchData()
152			})
153		}
154	}
155	initListeners(flat) {
156		const that = this;
157		this.$maintwo.forEach(a=>{
158			if(flat){
159					var checkboxList =  a.querySelectorAll('.unit-attr-search__content--checkbox');
160					checkboxList.forEach(i=>{
161						i.classList.remove('is_active')
162						var checkbox = i.querySelector('input[type="checkbox"]')
163						var checked = false
164						const checkboxInputType = parseInt(checkbox.getAttribute('data-input_type'));
165						const checkboxGroup = parseInt(checkbox.getAttribute('data-product_attr_id'));
166						const checkboxAttr = checkbox.getAttribute('data-attr_param') || 'attr';  // 属性参数
167						const checkboxDataId = parseInt(checkbox.getAttribute('data-id'));
168						that.checkedAttrs[checkbox.value] = {
169							product_attr_id: checkboxGroup,
170							attr: checkboxAttr,
171							id: parseInt(checkbox.getAttribute('data-id')),
172							input_type: checkboxInputType, // 单选/多选
173							content: checkbox.getAttribute('data-content'),
174							checked
175						};
176						// 显示隐藏
177						if (a.classList?.contains('icon-action-left-lighter')) {
178							evt.stopPropagation();
179							const hide_cls = 'unit-attr-search__content--hide';
180							a.classList.toggle('up');
181							a.parentNode.parentNode.querySelector('.unit-attr-search__content')?.classList?.toggle(hide_cls)
182						}
183					})
184			}else{
185				a.addEventListener('click', (evt) => {
186					console.log(evt.target)
187					const el = evt.target;
188					if(this.$droupDowm){
189						this.$droupDowm.classList.remove('show')
190					}
191					// 属性筛选
192					if (el.classList?.contains('unit-attr-search__content--checkbox') || el.parentNode.classList?.contains('unit-attr-search__content--checkbox')) {
193						evt.stopPropagation();
194						const pointer = evt.target.classList.contains('unit-attr-search__content--checkbox') ? evt.target : evt.target.parentNode;
195						const checkbox = pointer.querySelector('input[type="checkbox"]');
196						const checked = !(that.checkedAttrs[checkbox.value]?.checked);
197						const checkboxInputType = parseInt(checkbox.getAttribute('data-input_type'));
198						const checkboxGroup = parseInt(checkbox.getAttribute('data-product_attr_id'));
199						const checkboxAttr = checkbox.getAttribute('data-attr_param') || 'attr';  // 属性参数
200						const checkboxDataId = parseInt(checkbox.getAttribute('data-id'));
201						that.checkedAttrs[checkbox.value] = {
202							product_attr_id: checkboxGroup,
203							attr: checkboxAttr,
204							id: parseInt(checkbox.getAttribute('data-id')),
205							input_type: checkboxInputType, // 单选/多选
206							content: checkbox.getAttribute('data-content'),
207							checked
208						};
209						if (checkboxInputType === 2 && checked) {
210							// 单选 取消同分组下的其他checkbox选中状态
211							for (let k in that.checkedAttrs) {
212								const attr = that.checkedAttrs[k];
213								if (attr.product_attr_id === checkboxGroup && attr.checked && attr.id !== checkboxDataId) {
214									attr.checked = false;
215									that.checkedAttrs[k] = attr;
216								}
217							}
218						}
219						/**
220						 * @type {{[string]?: {product_attr_id: number, content: string[]}}}
221						 */
222						const attr_params = {};
223						const checkedBoxes = Object.values(that.checkedAttrs).filter(box => box?.checked && box.attr === 'attr');
224						[...new Set(checkedBoxes.map(box => box.product_attr_id))].forEach(group => attr_params[group] = {
225						product_attr_id: parseInt(group),
226						content: []
227						});
228						checkedBoxes.forEach(box => attr_params[box.product_attr_id]?.content?.push(box.content));
229						window.app.info.attr_params = Object.values(attr_params);
230						const attr_detail_id = Object.values(that.checkedAttrs).filter(box => box?.checked && box.attr === 'attr_detail_id').map(box => parseInt(box.id))
231						window.app.info.attr_detail_id = Array.from(new Set(attr_detail_id))
232						// const detailAttr
233						window.app.info.renderListView();
234					}
235					// 显示隐藏
236					if (el.classList?.contains('icon-action-left-lighter')) {
237						evt.stopPropagation();
238						const hide_cls = 'unit-attr-search__content--hide';
239						el.classList.toggle('up');
240						el.parentNode.parentNode.querySelector('.unit-attr-search__content')?.classList?.toggle(hide_cls)
241					}
242			
243				});
244			}
245		})
246		if(flat){
247			const attr_params = {};
248			const checkedBoxes = Object.values(that.checkedAttrs).filter(box => box?.checked && box.attr === 'attr');
249			[...new Set(checkedBoxes.map(box =>
249 box.product_attr_id))].forEach(group => attr_params[group] = {
250			product_attr_id: parseInt(group),
251			content: []
252			});
253			checkedBoxes.forEach(box => attr_params[box.product_attr_id]?.content?.push(box.content));
254			window.app.info.attr_params = Object.values(attr_params);
255			const attr_detail_id = Object.values(that.checkedAttrs).filter(box => box?.checked && box.attr === 'attr_detail_id').map(box => parseInt(box.id))
256			window.app.info.attr_detail_id = Array.from(new Set(attr_detail_id))
257			// const detailAttr
258			window.app.info.renderListView();
259		}
260	}
261	// 点击页面空白,折叠已展开栏目
262	initHideElement() {
263		document.querySelector('body').addEventListener('click', () => {
264			this.$itemSearchFilterBox.classList.remove('is_active')
265		})
266	}
267
268	initSort() {
269		this.$main.innerHTML = ''
270		this.$main.append(this.getSortListElement())
271	}
272
273	h(tag, props, text) {
274		const $item = document.createElement(tag)
275		for (const key in props) {
276			if (Object.hasOwnProperty.call(props, key)) {
277				const element = props[key];
278				if (key === 'class') {
279					if (Array.isArray(element)) $item.classList.add(...element)
280					else $item.classList.add(element)
281				}
282				else $item.setAttribute(key, element)
283			}
284		}
285		if (text) $item.innerHTML = text
286		return $item
287	}
288	/**
289	* 获取排序项 
290	* @param {Object} data 排序信息 
291	* @returns 
292	*/
293	getSortListElement() {
294		const $itemBox = this.h('div', { class: `${this.prefx}__filter` })
295		this.$itemSearchFilterBox = this.h('div', { class: `${this.prefx}__filter-text` })
296		const $span = this.h('span', {}, this.sortName)
297		this.$itemSearchFilterBox.append($span)
298		const $icon = this.h('span', { class: ['iconfont', 'icon-action-bottom-lighter', 'ml-1'] })
299		this.$itemSearchFilterBox.append($icon)
300		$itemBox.append(this.$itemSearchFilterBox)
301
302		const $filterPosiBox = this.h('div', { class: `${this.prefx}__filter-posi` })
303
304		const attr = { class: [`${this.prefx}__filter-posi-text`, `${this.prefx}__sanjiao`, `${this.prefx}__isChoose`] }
305		const $filterPosiBoxText = this.h('div', attr)
306
307		this.sortList.forEach((data, index) => {
308			const $pItem = this.h('p', {}, data.name)
309			if (data.active) $pItem.classList.add('is_active')
310			$filterPosiBoxText.append($pItem)
311		})
312		$filterPosiBox.append($filterPosiBoxText)
313		this.$itemSearchFilterBox.append($filterPosiBox)
314		return $itemBox
315	}
316	// 搜索框~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
317	createdSearchElement() {
318		// 清空旧的数据
319		this.$mainthree.innerHTML = ''
320		// 创建divBox
321		const $searchBox = document.createElement('div')
322		$searchBox.classList.add('input-group-right_slide')
323
324		const $inputGroup = document.createElement('div')
325		$inputGroup.classList.add('input-group-prepend-right_slide')
326		// 创建下拉属性项
327		this.$button = null
328		this.$button = document.createElement('button')
329		this.$button.classList.add('btn', 'btn-outline-secondary-right_slide')
330		const html = `<span class="btn-text text-truncate"> ${this.showSearchItemName} </span>
331			<span class="iconfont icon-action-bottom-lighter ml-1"></span>`
332		this.$button.innerHTML = html
333		$inputGroup.append(this.$button)
334
335		// 创建搜索文本项
336		this.$droupDowm = document.createElement('div')
337		this.$droupDowm.classList.add('dropdown-menu-right_slide')
338		$inputGroup.append(this.$droupDowm)
339
340		this.$input = null
341		this.$input = document.createElement('input')
342		this.$input.classList.add('form-control-right_slide')
343		$inputGroup.append(this.$input)
344		// 创建搜索图标
345		this.$incofont = null
346		this.$incofont = document.createElement('span')
347		this.$incofont.classList.add('iconfont', 'icon-action-search-lighter', 'btnSearch')
348
349		$searchBox.append($inputGroup)
350		$searchBox.append(this.$input)
351		$searchBox.append(this.$incofont)
352		this.$mainthree.append($searchBox)
353	}
354	async initLoadData() {
355		this.$droupDowm.innerHTML = ''
356		const params = { site_id: window.app.info.site.site_id, type: '1,2,3', status: 1, is_show: 1, language_code: window.app.info.site.language_code }
357		const url = '/product-attr/list-page'
358		const res = await this.utilts.request({ url, method: 'GET', params })
359		var resList = res.data.list || [];
360		var list = resList.filter(p => p.input_type === 1 && p.status && p.is_show)
361		list = list.map((p, i) => ({ id: p.id, name: p.sign || `name${i}`, type: p.input_type }))
362		if (list.length > 0){
363			this.product_attr_id = list[0].id
364			for (const item of list) {
365				const $item = document.createElement('div')
366				$item.classList.add('dropdown-item')
367				$item.setAttribute('data-id', item.id)
368				$item.setAttribute('href', '#')
369				$item.innerText = item.name
370				this.$droupDowm.append($item)
371				$item.onclick = () => {
372					this.sibling($item).forEach(a=>{
373						a.classList.remove('is_active')
374					})
375					$item.classList.add('is_active')
376					this.product_attr_id = item.id
377					const $btnText = this.$button.querySelector('.btn-text')
378					$btnText.innerText = item.name
379					this.$droupDowm.classList.toggle('show')
380				}
381			}
382		} else {
383			const tip = window.app.utilts.$t('no data')
384			this.$droupDowm.innerHTML = `<div class='dropdown-item' style='color:grey;text-align:center;'>${tip}<div>`
385		} 
386	}
387	sibling(elem) {
388		var r = [];
389		var n = elem.parentNode.firstChild;
390		for(; n; n = n.nextSibling) {
391			if(n.nodeType === 1 && n !== elem) {
392				r.push(n);
393			}
394		}
395		return r;
396	}
397	initEvent() {
398		// 下拉属性名改变事件
399		this.$button.addEventListener('click', (event) => {
400			event.stopPropagation()
401			this.$droupDowm.classList.toggle('show')
402		})
403
404		// 搜索图标点击查找事件
405		this.$incofont.addEventListener('click', (event) => {
406			event.stopPropagation()
407			this.searchData()
408		})
409
410		// 回车跳转
411		this.$input.addEventListener('keydown', (event) => {
412			event = event || window.event;
413			event.stopPropagation()
414			if (event.keyCode === 13) this.searchData()
415		})
416
417		// 点击页面空白,折叠已展开栏目
418		document.querySelector('body').addEventListener('touchmove', () => {
419			this.$droupDowm.classList.remove('show')
420		})
421	}
422		/**
423	 * 搜索数据
424	 */
425	searchData() {
426		window.app.info.pagination.page_number = 1
427		const content = this.$input.value
428		this.setAttrParams(content)
429		window.app.info.renderListView()
430		const product_list_el= this.$unit.parentNode.parentNode.parentNode.querySelector('[package-unit-type="product-list"]')
431		const list_el = this.$unit.parentNode.parentNode.parentNode.querySelector('[package-unit-type="list"]')
432		if (!list_el && !product_list_el) return
433		if(list_el) {
434			list_el.parentNode.parentNode.style.overflow = 'auto'
435			window.scrollTo({ top: list_el.getBoundingClientRect().top - 85})
436		}
437		if(product_list_el) window.scrollTo({ behavior: 'smooth', top: product_list_el.getBoundingClientRect().top - 85})
438	}
439
440	/**
441	 * 设置全局attr_params参数
442	 * @param {string} content 查找的内容 
443	 * @returns 
444	 */
445	setAttrParams(content) {
446		// 如果没有内容,删除存在的
447		let attrs = window.app.info.attr_params
448		if (!content) {
449			// 清空文本查找项
450			if (attrs.length > 0) {
451				window.app.info.attr_params = attrs.filter(p => typeof p.content !== 'string')
452			}
453			return
454		}
455		// 如果当前属性查找参数为空,添加一条数组记录
456		const params = { product_attr_id: this.product_attr_id, content }
457		if (attrs.length === 0) window.app.info.attr_params = [params]
458		else {
459			// 是否有文本查找项
460			const attrInfo = attrs.find(p => typeof p.content === 'string')
461			if (attrInfo) {
462				attrInfo.product_attr_id = this.product_attr_id
463				attrInfo.content = content
464			}
465			else window.app.info.attr_params.push(params)
466		}
467	}
468
469	/** 
470	 * 获取产品属性参数
471	 */
472}

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.