PageSourceSearch

https://www.minimotorizedvalve.com/assets/js/unit/search.js

js minimotorizedvalve.com collected 2026-10-05 22:27:15 UTC 38,138 bytes, 923 lines download raw bytes

1class ScriptSearch extends Script {
2  constructor(params) {
3    super(params)
4    this.siteType = params.templateType
5    this.templateType = params.siteType
6    this.pageInfo = JSON.parse(this.utilts.htmlDecode(params.pageInfo))
7  }
8  /** 初始化,支持异步 */
9  async init() {
10    await new Load('/assets/plugins/vue.min.js', 'application/javascript', {version_enabled: true})
11    this.initVue()
12  }
13  initVue() {
14    new Vue({
15      el: `#${this.attrId} .unit-search`,
16      /** data:基础的数据信息,filterSearch:过滤列表相关,searchUtilts:一些相关的基础操作 */
17      mixins: [this.data, this.filterSearch, this.searchUtilts],
18      data: {
19        template_type: this.templateType,
20        /** 查找条件 */
21        searchWhere: {
22          return_category: 0, // 返回分类
23          site_id: window.app.info.site.site_id,
24          page_size: 12,
25          page_number: 1,
26          status: 1,
27          attr_detail_id: null,
28          attr: null,
29          attr_linkage_id: null,
30          page_category_id: '',
31          keyword: '',
32          columns: '',
33          sort: ''
34        },
35        /** 排序类型 */
36        sortTypeList: [
37          { type: 'product', key: 'sort desc,create_time desc', value: Utilts.ins().$t('Default') },
38          { type: 'document', key: 'sort desc,create_time desc', value: Utilts.ins().$t('Default') },
39          { type: 'all', key: 'id desc', value: Utilts.ins().$t('Newest') },
40          { type: 'product', key: 'price asc', value: Utilts.ins().$t('Lowest Price') },
41          { type: 'product', key: 'price desc', value: Utilts.ins().$t('Highest Price') },
42          { type: 'product', key: 'order desc', value: Utilts.ins().$t('Hot Sale') },
43          { type: 'product', key: 'favorite desc', value: Utilts.ins().$t('Most Popular') },
44          { type: 'article', key: 'id asc', value: Utilts.ins().$t('Earliest') },
45          { type: 'video', key:  'id asc', value: Utilts.ins().$t('Earliest') },
46          { type: 'video', key: 'reads desc', value: Utilts.ins().$t('Highest Play') },
47          { type: 'video', key: 'reads asc', value: Utilts.ins().$t('Lowest Play') },
48        ],
49        /** 查找类型 */
50        searchType: [
51          { name: Utilts.ins().$t('Product'), type_id: 2, is_show: true, type: 'product' },
52          { name: Utilts.ins().$t('Article'), type_id: 3, is_show: false, type: 'article' },
53          { name: Utilts.ins().$t('Video'), type_id: 13, is_show: false, type: 'video' },
54          { name: Utilts.ins().$t('Document'), type_id: 14, is_show: false, type: 'document' }
55        ],
56        // 过滤项
57        searchItem: {
58          features: [], // 特色参数列表
59          patterns: [], // 款式属性列表
60          attrs: [], // 属性参数列表
61        },
62        /** 选中项 */
63        selected: {
64          featuresId: 0, // 选中的特色参数属性
65          patterns: [], // 选中的款式属性
66          attrs: [] // 选中的属性列表
67        },
68        banner_img: '/assets/images/affiliate/articleDefaultImage.png',
69        is_inquiry_captcha:0,
70        is_record_input:false  // 询盘输入状态
71      },
72      created() {
73        this.initData()
74      },
75      computed: {
76        // 计算属性的 getter
77        sortLis() {
78          var list = JSON.parse(JSON.stringify(this.sortTypeList.filter(p => p.type === this.currentSearchType || p.type === 'all')))
79          if(this.currentSearchType=='product'){
80            list.map(a=>{
81              if(a.type === 'all'){
82                a.key = 'create_time desc,id desc'
83              }
84            })
85          }
86          if(this.template_type==='b2b'&&this.currentSearchType=='product'){
87            list = [
88              { type: 'all', key: 'create_time desc,id desc', value: Utilts.ins().$t('Newest') },
89              { type: 'product', key: 'sort desc,create_time desc', value: Utilts.ins().$t('Default') }
90            ]
91          }
92          return list
93        }
94      },
95      mounted() {
96        this.initHideCategory()
97      },
98      methods: {
99        handleDownload(item){
100          var that = this;
101          Utilts.ins().request({
102            prefix: 'jmc',
103            stringify: false,
104            url: '/download/get-url',
105            method: 'GET',
106            params: {
107              site_id: window.app.info.site.site_id,
108              id: item.id
109            }
110          }).then(function (res) {
111            console.log('/download/get-url',res)
112            if (res && res.data && res.data.hasOwnProperty('download_status')) {
113              // 0:不限;1:提交询盘才下载;2:登录后才能下载
114              const url = res.data.url
115              const download_status = res.data.download_status
116              const DOWNLOAD_STATUS = {
117                UN_LIMIT: 0,
118                LIMIT_INQUIRY: 1,
119                LIMIT_LOGIN: 2
120              }
121              if (url) {
122                window.open('/uncache/download.html?file=' + url, '_blank')
123              } else if (download_status === DOWNLOAD_STATUS.LIMIT_INQUIRY) {
124                const files = Utilts.ins().getInquiredFiles()
125                if (files[item.id]) {
126                  window.open('/uncache/download.html?file=' + files[item.id], '_blank')
127                } else {
128                  that.initInquiry(item.id)
129                }
130              } else if (download_status === DOWNLOAD_STATUS.LIMIT_LOGIN) {
131                sessionStorage.setItem('prev_url', location.pathname)
132                const msgBox = new Message()
133                msgBox.info(window.app.utilts.$t("Please login in first"))
134                setTimeout(function () {
135                  msgBox.close()
136                  location.href = '/login.html'
137                }, 2000)
138              }
139            }
140          })
141        },
142        async initData() {
143          const that = this
144          // 初始显示页面栏目
145          let type_id = 2
146          let showTabsID = []
147          if (this.sortType) {
148            type_id = this.sortType.split(',')[0] || 2
149            showTabsID = this.sortType.split(',').map(p => p * 1)
150          }
151          // 如果设置了排序tabs,则根据排序tabs来获取,将2,3,13,14 => [2, 3, 13, 14]
152          let filterType = []
153          // 这一步用于排序
154          if (showTabsID.length) {
155            showTabsID.forEach(item => {
156              const type = this.searchType.find(p => p.type_id === item)
157              if (type) {
158                filterType.push(type)
159              }
160            })
161            this.$set(this, 'searchType', filterType)
162          }
163
164          await this.getPageCategory(type_id * 1)
165          // 加载相应数据
166          // this.getSearchList()
167          // 初始产品过滤条件
168          this.initProductFilter()
169        },
170        /** 点击tab, 获取产品,文章,视频类别 */
171        async getPageCategory(type_id) {
172          const that = this
173          this.isNoData = false
174          // const data = await ScriptSearchApi.ins().getPageCategory(type_id)
175          // if (data.length > 6) this.isUpCategory = true
176          // this.$set(this, 'categoryList', data)
177          // this.initShowCategory(0)
178          this.sort = 'id desc'
179          if(type_id=='2'){
180            this.sort = 'create_time desc,id desc'
181          }
182          this.showSort = Utilts.ins().$t('Newest')
183          this.selected.pattern = []
184          // 根据不同tab类型调不同列表接口
185          const list = this.searchType.map(item => {
186            if (type_id === item.type_id) {
187              item.is_show = true
188              this.currentSearchType = item.type
189            } else item.is_show = false
190            return item
191          })
192          this.$set(this, 'searchType', list)
193          // 切换tab,清空分类字段
194          this.page_category_id = ''
195          this.page_number = 1
196          this.getSearchList({
197            return_category: 1
198          }).then(function (data) {
199            const page_category = data.page_category || []
200            if (page_category.length > 6) that.isUpCategory = true
201            // console.log('/// ===== page_category', page_category)
202            that.$set(that, 'categoryList', page_category)
203            that.initShowCategory(0)
204          })
205        },
206        /** 根据栏目分类查找 */
207        getPageTypeList(page_category_id) {
208          this.page_category_id = page_category_id
209          this.page_number = 1
210          this.getSearchList()
211          this.isShowFilter = !this.isShowFilter
212        },
213        /** 获取产品,文章,或视频列表数据 */
214        getSearchList(params = {}) {
215          if (typeof params !== 'object') {
216            params = {}
217          }
218          this.searchLoading = true
219          this.setSearchParams()
220          return ScriptSearchApi.ins().getSearchList(Object.assign({}, this.searchWhere, params), this.currentSearchType)
221            .then(data => {
222              this.searchLoading = false
223              if (Array.isArray(data)) return
224              this.isNoData = !!data.total
225              this.$set(this.page, 'page_size', data.page_size)
226              this.$set(this.page, 'page_number', data.page_number)
227              this.$set(this.page, 'page_count', data.page_count)
228              this.$set(this.page, 'page_total', data.total)
229              // 如果是视频
230              if (this.currentSearchType === 'video') {
231                data.list.forEach(item => item.thumb = item.thumb_prefix)
232              }
233              let compress = window.app.info.site.compress__ratio || '100'
234              compress = compress.split(',').sort().reverse()
235              data.list.forEach(item => {
236
237                this.changePrice(item.price)
238              })
239              this.$set(this, 'productList', data)
240              return data
241            })
242            .catch(err => {
243              this.searchLoading = false
244              new Message().error(err)
245            })
246        },
247        // 处理传参
248        setSearchParams() {
249          // 关键字
250          if (this.keyword) this.searchWhere.keyword = this.keyword
251          else delete this.searchWhere.keyword
252          // 栏目id
253          if (this.page_category_id !== '') this.searchWhere.page_category_id = this.page_category_id
254          else delete this.searchWhere.page_category_id
255          // 排列
256          if (this.sort) this.searchWhere.sort = this.sort === 'All' ? '' : this.sort
257          // 页数
258          this.searchWhere.page_number = this.page_number
259          // 语言
260          this.searchWhere.language_code = window.app.info.site.language_code
261          // 文章
262          if (this.currentSearchType === 'article') this.$set(this.searchWhere, 'content_type', 3)
263          else delete this.searchWhere.content_type
264
265          // 新传参字段
266          if (this.currentSearchType === 'product') {
267            this.searchWhere.columns = 'title,summary,subtitle,price'
268            // 不存在款式筛选,清空字段
269            if (this.selected.patterns.length > 0) {
270              this.$set(this.searchWhere, 'attr_detail_id', this.selected.patterns.join(','))
271            } else delete this.searchWhere.attr_detail_id
272            // 不存在属性参数筛选,清空字段
273            if (this.selected.attrs.length > 0) {
274              this.$set(this.searchWhere, 'attr', JSON.stringify(this.selected.attrs))
275            } else delete this.searchWhere.attr
276            // 设置特色参数,存在设置,不存在删除
277            if (this.selected.featuresId) {
278              this.$set(this.searchWhere, 'attr_linkage_id', this.selected.featuresId)
279            } else if (this.attrLinkageId) {
280              this.$set(this.searchWhere, 'attr_linkage_id', Number(this.attrLinkageId))
281            } else delete this.searchWhere.attr_linkage_id
282          } else {
283            delete this.searchWhere.columns
284            delete this.searchWhere.attr_detail_id
285            delete this.searchWhere.attr
286            delete this.searchWhere.attr_linkage_id
287          }
288
289        },
290        /** 创建询盘 */
291        initInquiry(id) {
292          const that = this
293          const inquiryPopupContent = `
294            <form method="post" id="inquiry-unit-${this.attrId}" class="needs-validation" inquiry="" novalidate="">
295              <input type="hidden" name="content_id" value="">
296              <div class="form-row">
297                <div class="unit-form__title">${window.app.utilts.$t('Send your inquiry')}</div>
298                <div class="unit-form__item form-group contacts col col-12 col-md-12 col-xl-12">
299                  <label class="unit-form__item-inner">
300                    <input class="unit-form__control form-control" type="text" name="contacts" autocomplete="off" placeholder="name" maxlength="200" required="">
301                    <div class="invalid-feedback">${window.app.utilts.$t('Please enter your name')}!</div>
302                    <span class="unit-form__label col-form-label">${window.app.utilts.$t('name')}</span>
303                  </label>
304                </div>
305                <div class="unit-form__item form-group email col col-12 col-md-12 col-xl-12">
306                  <label class="unit-form__item-inner">
307                    <input class="unit-form__control form-control" type="email" name="email" autocomplete="off" placeholder="email" maxlength="200" required="" pattern="[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)*@[a-zA-Z0-9_]+(-?[a-zA-Z0-9\\.]+)*(\\.[a-zA-Z]{2,})$">
308                    <div class="invalid-feedback">${window.app.utilts.$t('Please enter a valid email address')}!</div>
309                    <span class="unit-form__label col-form-label">${window.app.utilts.$t('email')}</span>
310                  </label>
311                </div>
312                <div class="unit-form__item form-group phone col col-12 col-md-12 col-xl-12">
313                  <label class="unit-form__item-inner">
314                    <input class="unit-form__control form-control" type="text" name="phone" autocomplete="off" placeholder="phone" maxlength="200" required="">
315                    <div class="invalid-feedback">${window.app.utilts.$t('Please enter a valid phone')}!</div>
316                    <span class="unit-form__label col-form-label">${window.app.utilts.$t('phone')}</span>
317                  </label>
318                </div>
319                <div class="unit-form__item form-group company_name col col-12 col-md-12 col-xl-12">
320                  <label class="unit-form__item-inner">
321                    <input class="unit-form__control form-control" type="text" name="company_name" autocomplete="off" placeholder="company name" maxlength="200">
322                    <div class="invalid-feedback">${window.app.utilts.$t('input must not exceed 200 in length')}!</div>
323                    <span class="unit-form__label col-form-label">${window.app.utilts.$t('Company Name')}</span>
324                  </label>
325                </div>
326                <div class="unit-form__item form-group col-12">
327                  <label class="unit-form__item-inner">
328                    <textarea class="unit-form__control form-control" rows="5" name="content" maxlength="65530" placeholder="content" required="" minlength=""></textarea>
329                    <div class="invalid-feedback">${window.app.utilts.$t('the content cannot be empty and cannot exceed 65530')}!</div>
330                    <span class="unit-form__label col-form-label">${window.app.utilts.$t('content')}</span>
331                  </label>
332                </div>
333
334                <div class="unit-form__item unit-form__item-submit form-group col">
335                  <div class="unit-form__submit-wrap" button-style="2">
336                    <div class="base-button">
337                      <button class="base-button__inner btn" type="submit">
338                        <div class="d-inline-block">${window.app.utilts.$t('send inquiry now')}</div>
339                      </button>
340                    </div>
341                  </div>
342                </div>
343              </div>
344            </form>`
345
346          let inquiryPopupNode = document.getElementById('inquiry-popup')
347          if (!inquiryPopupNode) {
348            inquiryPopupNode = document.createElement('div')
349            inquiryPopupNode.innerHTML = `
350            <div class="unit-inquiry-popup__window">
351              <div class="unit-inquiry-popup__close">×</div>
352              <div class="unit-inquiry-popup__content" label-style="${that.label_style}">${inquiryPopupContent}</div>
353            </div>`
354
355            inquiryPopupNode.setAttribute('id', 'inquiry-popup')
356            inquiryPopupNode.className= "unit-inquiry-popup__window-wrap"
357            inquiryPopupNode.getElementsByClassName("unit-inquiry-popup__close")[0].addEventListener('click', function() {
358              inquiryPopupNode.classList.remove("show")
359            })
360
361            this.$submit = inquiryPopupNode.querySelector('[type="submit"]')
362
363            inquiryPopupNode.querySelector('form').addEventListener('submit', async (event) => {
364              event.preventDefault()
365              // 验证表单信息是否合法,不合法不提交
366              if (!this._inquirySet(event, inquiryPopupNode.querySelector('form'))) return
367              Utilts.ins().setBtnLoadingStatus(this.$submit, true)
368              // 设置,获取要保存的表单信息
369              const { preset_config } = this._inquiryConfig(inquiryPopupNode.querySelector('form'))
370              // 记录提交记录
371              await Utilts.ins().setInquiryRecord('inquiry_submit', this._getConfigParams(preset_config))
372              this._inquiryRequest(preset_config)
373            })
374
375            inquiryPopupNode.querySelectorAll('input').forEach($el => {
376              $el.addEventListener('focus', () => {
377                if (!that.is_record_input) {
378                  that.is_record_input = true
379                  Utilts.ins().setInquiryRecord('inquiry_start').then(function(){})
380                }
381              })
382            })
383
384            inquiryPopupNode.addEventListener('wheel', function (e) {
385              e.stopPropagation()
386              if (!e.target.closest('.unit-inquiry-popup__window')) {
387                e.preventDefault()
388              }
389            })
390
391            inquiryPopupNode.addEventListener('touchmove', function (e) {
392              e.stopPropagation()
393              if (!e.target.closest('.unit-inquiry-popup__window')) {
394                e.preventDefault()
395              }
396            })
397
398            inquiryPopupNode.querySelectorAll('[type="email"]').forEach(formItem => {
399              formItem.addEventListener('blur', function () {
400                formItem.value = formItem.value.toLowerCase()
401              })
402            })
403
404            document.body.appendChild(inquiryPopupNode)
405          }
406
407          inquiryPopupNode.querySelector('[name="content_id"]').setAttribute('value', id
407)
408          inquiryPopupNode.classList.add('show')
409        },
410        /** 获取表单要提交的参数 */
411        _getConfigParams(preset_config) {
412          let params = Object.assign({}, preset_config, {
413            site_id: window.app.info.site.site_id,
414            visitor_code: window.app.info.user.visitor_code,
415            visitor_id: window.app.info.user.visitor_id,
416            ip: window.app.info.user.visitor_ip,
417            inquiry_record: Utilts.ins().getDevice(),
418            // member_id: window.app.info.user.user_id,
419            content_type: window.app.info.source.source_content_type,
420            page_url: window.app.info.tempValidPage.href,
421            page_type: window.app.info.page.page_type,
422            source: window.app.info.source.source_result,
423            language_code: window.app.info.site.language_code
424          })
425          return params
426        },
427        // 询盘表单提交
428        async _inquiryRequest(preset_config) {
429          const params = this._getConfigParams(preset_config)
430          params['need'] = 'download_url'
431          const utilts = window.app.utilts
432          const that = this
433          const _handleInquiry = async function (captcha, flagRetry) {
434            if (captcha) {
435              // 腾讯验证
436              const captcha_token = await Utilts.ins().checkTCaptcha('inquiry')
437              if (captcha_token) params.token = captcha_token
438              else {
439                utilts.setBtnLoadingStatus(that.$submit, false)
440                return
441              }
442            }
443            const stringify = 1
444            const url = '/inquiry/insert'
445            const method = 'POST'
446            if(sessionStorage.getItem('ip')){
447              params.ip = sessionStorage.getItem('ip')
448            }
449            return utilts.request({stringify, url, method, params})
450                .then(res => {
451                  utilts.recordClientInquiredTimes()
452                  that.handleInquireSuccess(res, params)
453                })
454                .catch((res) => {
455                  if (res && res.code && parseInt(res.code) === 103) {
456                    // 103 验证码
457                    if (flagRetry) {
458                      // 防止无限弹验证码
459                      throw new Error('retry captcha')
460                    }
461                    return _handleInquiry(true, true)
462                  } else if (res && res.msg) {
463                    new Modal().warning(res.msg, 'Prompt').open()
464                  } else {
465                    console.error(res)
466                    new Modal().warning('Unknown error', 'Prompt').open()
467                  }
468                  utilts.setBtnLoadingStatus(that.$submit, false)
469                })
470          }
471          let needleCaptcha = false
472          const cfgRes = await this.getSiteData()
473          if (cfgRes && cfgRes.data && cfgRes.data.tencent_verify_id) {
474            // 设置最新的验证码客户端id
475            window.app.info.site.tencent_verify_id = cfgRes.data.tencent_verify_id
476          }
477          if (cfgRes.data && cfgRes.data.site_config) {
478            const site_config = cfgRes.data.site_config
479            const page_type = window.app.info.page.page_type || ''
480            const is_landing_page = page_type === 'landing_page'
481            const captcha_switch = is_landing_page ? site_config.ads_inquiry_captcha_switch : site_config.inquiry_captcha_switch
482            const first_no_check = is_landing_page ? site_config.ads_inquiry_captcha_first_no_check_switch : site_config.inquiry_captcha_first_no_check_switch
483            const count = utilts.getClientInquiredTimes()
484            needleCaptcha = captcha_switch ? ( first_no_check ? count > 0 : true ) : false
485            if (site_config.inquiry_success_redirect_time && !isNaN(site_config.inquiry_success_redirect_time)) {
486              sessionStorage.setItem('success_redirect_time', Number(site_config.inquiry_success_redirect_time))
487            }
488          }
489          return _handleInquiry(needleCaptcha, false)
490        },
491        _inquirySet(event, $form) {
492          event.preventDefault()
493          event.stopPropagation()
494          // 装修模式下不能保存表单
495          if (window.app.info.utilts.checkDesign()) return false
496          $form.classList.add('was-validated')
497          let success = true
498          // 验证表单项
499          for (const $formItem of $form) {
500            if (!$formItem.checkValidity()) {
501              success = false
502              break
503            }
504          }
505          return success
506        },
507        // 获取config
508        _inquiryConfig($form) {
509          // 获取要保存的信息
510          var preset_config = {} //默认的表单项
511          const formData = new FormData($form)
512          const serializeArray = []
513          for (const item of formData) {
514            serializeArray.push({ name: item[0], value: item[1] })
515          }
516          // 区分自定义表单元素和系统表单元素
517          serializeArray.forEach(function (item, index) {
518            preset_config[item.name] = item.value
519          })
520          return { preset_config }
521        },
522         /**
523         * 询盘成功
524         * @param res
525         * @param {{email?:string}} params
526         */
527        handleInquireSuccess(res, params) {
528          try {
529            const download_url = (res && res.data && res.data.download_url) || ''
530            Utilts.ins().setBtnLoadingStatus(this.$submit, false)
531            Utilts.ins().setGtag('begin_inquiy')
532            const contentId = params.content_id || 0
533            Utilts.ins().recordInquiredFile(contentId, download_url)
534            window.app.info.user.guest_id = res.data.member_id
535            sessionStorage.setItem('prev_url', location.pathname+location.search)
536            window.open('/uncache/download.html?file=' + res.data.download_url, '_blank')
537            sessionStorage.setItem('prev_inquire_email', (params && params.email) || '')
538            window.location.href = globalThis.Server.getRinseHref('/inquire_success.html', window.app.info.site)
539          } catch (err) {
540            console.error("err.message", err.message)
541          }
542        },
543        /**
544         * 获取是否开启广告页询盘验证
545         * 迁移到 Utilts.getSiteData
546         * @deprecated
547         * @returns {Promise<unknown>}
548         */
549        async getSiteData() {
550          const params = {
551            site_id: window.app.info.site.site_id
552          }
553          return await Utilts.ins().request({
554            url: '/site/info',
555            method: 'get',
556            params
557          }).then(res => {
558            if (res.code == 0) {
559              this.is_inquiry_captcha = res.data.inquiry_captcha
560            }
561            return res
562          })
563        },
564      }
565    })
566  }
567
568  /** 基本的一些数据 */
569  get data() {
570    return {
571      data: {
572        page: this.pageInfo,
573        site_type: this.siteType,
574        label_style:this.labelStyle,
575        isHideSide: {
576          category: false,
577          features: false,
578        },
579        isUpCategory: false,
580        categoryList: [],
581        thirdCategoryList: [],
582        productList: [],
583        page_number: 1,
584        keyword: this.utilts.getParamsByUrl('keyword') || '',
585        sortType: this.utilts.getParamsByUrl('sortType') || '',
586        type: '',
587        sort: Utilts.ins().$t('Newest'),
588        showSort: Utilts.ins().$t('Newest'),
589        page_category_id: '',
590        closeDrop: true,
591        listQueue: 'column',
592        isShowFilter: false,
593        currentSearchType: 'product',
594        searchLoading: false,
595        isNoData: false,
596        attrLinkageId: this.utilts.getParamsByUrl('linkage_id') || 0
597      }
598    }
599  }
600
601  /** 产品过滤相关的属性参数 */
602  get filterSearch() {
603    return {
604      methods: {
605        /** 初始产品过滤条件 */
606        initProductFilter() {
607          // 款式列表
608          this.getPatternList()
609          // 属性列表
610          this.getAttrList()
611          // 特色参数列表
612          // this.getFeaturesList()
613          this.initFeaturesList()
614        },
615        async initFeaturesList() {
616          await new Load('/assets/plugins/quick-search.js', 'application/javascript', {version_enabled: true})
617          let unit = new PluginQuickSearch({ attrId: this.attrId, type: 1 })
618          unit = await unit.init({
619            onChange: () => {
620              this.$set(this.selected, 'featuresId', unit.searchId)
621              if (unit.searchId) this.getSearchList()
622            }
623          })
624          this.$refs.features.append(unit.$target)
625          this.$set(this.searchItem, 'features', unit.patternList)
626        },
627        // 属性参数
628        getAttrList() {
629          ScriptSearchApi.ins().getAttrList(2)
630            .then(data => {
631              data.is_show = true
632              const list = data.list.filter(p => !!p.status)
633              this.$set(this.searchItem, 'attrs', list)
634            })
635            .catch(err => new Message().error(err))
636        },
637        // 款式参数
638        getPatternList() {
639          ScriptSearchApi.ins().getAttrList(3)
640            .then(data => {
641              const list = data.list.filter(p => !!p.status)
642              this.$set(this.searchItem, 'patterns', list)
643            })
644            .catch(err => new Message().error(err))
645        },
646        // 选择、取消款式参数
647        changePatternSearch(attr_id, data, input_type) {
648          data.is_active = !data.is_active
649          if (data.is_active) {
650            const id = this.selected.patterns.find(id => id === data.id)
651            if (!id) { this.selected.patterns.push(data.id) }
652          } else {
653            this.selected.patterns = this.selected.patterns.filter(id => id !== data.id)
654          }
655          this.getSearchList()
656        },
657        // 选择、取消属性参数
658        changeAttrSearch(parent_id, data, type) {
659          data.is_active = !data.is_active
660          if (data.is_active) {
661            //将选中的信息添加到数组中,如果不存在
662            this.addAttrSearch(parent_id, data, type)
663            // 单选时,只选中自己其它的不选中
664            this.singSelect(parent_id, data, type)
665          } else {
666            // 删除
667            this.removeAttrSearch(parent_id, data)
668          }
669          this.getSearchList()
670        },
671        addAttrSearch(parent_id, data, type) {
672          //将选中的信息添加到数组中,如果不存在
673          // this.selected.attrs = [{product_attr_id:'1', content:['1','2]}]
674          const attr = this.selected.attrs.find(item => item.product_attr_id === parent_id)
675          if (!attr) { // 不存在product_attr_id,添加一个新的项
676            this.selected.attrs.push({ product_attr_id: parent_id, content: [data.content] })
677          } else if (!attr.content.includes(data.content)) {
678            // 存在product_attr_id,同时content不包含时添加到content
679            if (type === 1 || type === 2) attr.content.length = 0
680            attr.content.push(data.content)
681          }
682        },
683        removeAttrSearch(parent_id, data) {
684          const attr = this.selected.attrs.find(item => item.product_attr_id === parent_id)
685          if (attr.content.includes(data.content)) {
686            attr.content = attr.content.filter(p => p !== data.content)
687            if (attr.content.length === 0) {
688              this.selected.attrs = this.selected.attrs.filter(item => item.product_attr_id !== parent_id)
689            }
690            this.$set(this.selected, 'attrs', this.selected.attrs)
691          }
692        },
693        singSelect(parent_id, data, type) {
694          // 单选时,只选中自己其它的不选中
695          if (type === 1 || type === 2) {
696            const attrItem = this.searchItem.attrs.find(item => item.id === parent_id)
697            attrItem.attr_value.forEach(item => item.is_active = item.id === data.id)
698          }
699        }
700      }
701    }
702  }
703
704  /** 一些页面公共相关的操作 */
705  get searchUtilts() {
706    return {
707      methods: {
708        changeFilter(val, showVal) {
709          this.$set(this, 'sort', val)
710          this.$set(this, 'showSort', showVal)
711          this.closeDrop = false
712          this.getSearchList()
713        },
714        /** 筛选下拉 */
715        openDrop(event) {
716          this.closeDrop = !this.closeDrop
717          this.addModuleLevel(!this.closeDrop)
718          event.stopPropagation()
719        },
720        /** 筛选右侧列表展示 */
721        changeListQueue(type) {
722          this.$set(this, 'listQueue', type)
723        },
724        /** 分类超过六个,折叠并显示展开按钮 */
725        getMoreCategory() {
726          this.isUpCategory = false
727        },
728        onPagination(index) {
729          this.page_number = index
730          this.getSearchList()
731        },
732        showFilter() {
733          this.isShowFilter = !this.isShowFilter
734          this.addModuleLevel(this.isShowFilter)
735        },
736        /** 产品价格设置 */
737        changePrice(data) {
738          if (!data) { return }
739          data.cost_max = Number((data.cost_max / 100).toFixed(2))
740          data.cost_min = Number((data.cost_min / 100).toFixed(2))
741          data.selling_max = Number((data.selling_max / 100).toFixed(2))
742          data.selling_min = Number((data.selling_min / 100).toFixed(2))
743        },
744        /** 显示栏目分类2,3级 */
745        async showNavChild(event, id) {
746          await this.initShowCategory(id)
747          if (event) this.setCategoryPosition(event)
748        },
749        setCategoryPosition(event) {
750          const $parent_item = event.target.parentNode.parentNode
751          const $parent = $parent_item.parentNode
752          const $target = this.$refs.thirdCategory
753          const top = $parent.parentNode.offsetTop - $parent.parentNode.scrollTop
754          const left = $parent_item.offsetLeft + $parent_item.clientWidth + document.querySelector('.unit-search__category').clientWidth
755          $target.style.top = top + 'px'
756          $target.style.left = left + 'px'
757          $target.classList.add('is_active')
758          if ($parent.offsetHeight + this.getElementTop($parent) > document.body.offsetHeight) {
759            $parent.style.bottom = '0px'
760            $parent.style.top = 'auto'
761          }
762        },
763        initShowCategory(id) {
764          this.categoryList = this.categoryList.map(item => {
765            if (item.id === id) item.is_show = !item.is_show
766            else item.is_show = false
767            if (item.children) {
768              item.children.map(son => {
769                if (son.id === id) {
770                  son.is_show = !son.is_show
771                  item.is_show = true
772                  // 拷贝一份三级栏目数据
773                  if (son.is_show) this.thirdCategoryList = son.children
774                  else this.thirdCategoryList = []
775                }
776                else son.is_show = false
777              })
778            }
779            return item
780          })
781        },
782        // 点击页面空白,折叠已展开栏目
783        initHideCategory() {
784          document.querySelector('body').addEventListener('click', () => {
785            this.initShowCategory(0)
786            this.$refs.thirdCategory.classList.remove('is_active')
787            if (!this.closeDrop) this.closeDrop = true
788          })
789        },
790        // 有弹窗/下拉升高module层级
791        addModuleLevel(data) {
792          const $module = document.querySelector('[package-type="main"] [package-group="module"]')
793          if (data) $module.classList.add('active')
794          else $module.classList.remove('active')
795        },
796        getElementTop(element) {
797          let actualTop = element.offsetTop
798          let current = element.offsetParent
799          while (current !== null) {
800            actualTop += current.offsetTop
801            current = current.offsetParent
802          }
803          return actualTop
804        }
805      }
806    }
807  }
808}
809
810class ScriptSearchApi {
811  constructor() {
812    this.utilts = Utilts.ins()
813  }
814  /** 单例模式 */
815  static ins() {
816    if (!this.instance) {
817      return this.instance = new ScriptSearchApi()
818    }
819    return this.instance
820  }
821  /** 页面栏目 */
822  getPageCategory(type_id) {
823    return new Promise((resolve, reject) => {
824      this.utilts.request({
825        url: '/page-category/list-child',
826        method: 'GET',
827        params: {
828          site_id: window.app.info.site.site_id,
829          relate_type: type_id,
830          language_code: window.app.info.site.language_code,
831        }
832      })
833        .then(res => {
834          if (res.code === 0) resolve(res.data)
835          else resolve([])
836        })
837        .catch(err => reject(err))
838    })
839  }
840  getSearchList(params, type) {
841    return new Promise((resolve, reject) => {
842      type = type=='document'?'download':type
843      this.utilts.request({
844        prefix: type === 'video' ? 'qqt' : '',
845        url: `/${type}/list-page-by-search`,
846        method: 'POST',
847        params
848      })
849        .then(res => {
850          if (res.code === 0) {
851            if (Array.isArray(res.data)) resolve([])
852            res.data = res.data || {}
853            res.data.list = res.data.list || []
854            res.data.list = res.data.list.map(p => this.setResultInfo(p, type))
855            resolve(res.data)
856          } else {
857            resolve([])
858          }
859        })
860        .catch(err => reject(err))
861    })
862  }
863  replaceImgDomain(url) {
864    const site = app.info.site
865    return globalThis.Server.replaceImgDomain(url, site.prefix_domain,  site.is_replace_domain)
866  }
867  setResultInfo(info, type) {
868    info.price = info.price || {}
869    const data = {
870      id: info.id,
871      type: type,
872      title: info.title,
873      subtitle: info.subtitle || '',
874      summary: info.summary || '',
875      thumb: this.replaceImgDomain(info.thumb),
876      page_url: info.page_url || '',
877      page_url_suffix: info.page_url_suffix || '',
878      src_url_prefix: info.src_url_prefix || '',
879      thumb_prefix: info.thumb_prefix || '',
880      reads: info.reads || 0,
881      price: {
882        cost_min: info.price.cost_min || 0,
883        cost_max: info.price.cost_max || 0,
884        selling_min: info.price.selling_min || 0,
885        selling_max: info.price.selling_max || 0,
886      }
887    }
888    data.thumb_prefix = this.replaceImgDomain(info.thumb_prefix)
889    // ai,聚合不显示价格
890    if (type === 'product' && info.content_type !== 2) {
891      data.price.cost_min = 0
892      data.price.cost_max = 0
893      data.price.selling_min = 0
894      data.price.selling_max = 0
895    }
896    return data
897  }
898  getAttrList(type_id) {
899    return new Promise((resolve, reject) => {
900      this.utilts.request({
901        url: '/product-attr/list-page',
902        method: 'GET',
903        params: {
904          site_id: window.app.info.site.site_id,
905          type: type_id,
906          status:1,
907          is_show: 1,
908          language_code:  window.app.info.site.language_code
909        }
910      })
911        .then(res => {
912          if (res.code === 0) {
913            if (res.data.list.length > 0) {
914              res.data.list = res.data.list.filter(p => !!p.status)
915            }
916            resolve(res.data)
917          }
918          else resolve({ data: { list: [] } })
919        })
920        .catch(err => reject(err))
921    })
922  }
923}

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.