PageSourceSearch

https://www.xtyamusement.com/src/page.js

js xtyamusement.com collected 2026-10-07 23:43:06 UTC 20,475 bytes, 523 lines download raw bytes

1import { getPageData, getCategoryData, setPageData, getPartnerLink, getDocumentPage, getProductMatchData } from './api/page.js'
2import { getContentCounts } from './api/site.js'
3import { getPageCategoryList, getVideoListPageBySearch, getArticleListPageBySearch, getPolymerizeList, getProductListPageBySearch, getSitemapTagsList, getFAQListPageBySearch } from './api/content.js'
4import { calcPathName } from './function.js'
5import { checkDetail, checkAnimat, getBasePagePath, getPageNumber, getPageId } from '../config/index.js'
6import localData from '../dist/js/data.js'
7import { pruneHiddenHtml } from './prune-hidden-html.js'
8
9class Page {
10  /**
11  * 构造函数
12  */
13  constructor(ctx) {
14    this.ctx = ctx
15    this.pageData = {}
16  }
17
18  /**
19   * 初始化
20   */
21  async init() {
22    if (this.ctx.state.postCtxState && this.ctx.state.postCtxState.page) {
23      return this.ctx.state.postCtxState.page
24    }
25
26    let url_path = this.ctx.path
27    // 如果是子目录形式, 路径中去掉小语种前缀
28    if (this.ctx.state.site.domain_mode === 2 && this.ctx.state.site.lang_prefix !== '/') {
29      url_path = this.ctx.path.replace(this.ctx.state.site.lang_prefix, '')
30    }
31    // 请求页面参数
32    const pageParams = {
33      language_code: this.getLanguageCode(),
34      site_id: this.ctx.state.site.site_id,
35      url_path: url_path || '/',
36      domain: this.ctx.state.site.domain
37    }
38    if (/\/product[_-]lives(|[_-]list\d+)\.html/.test(url_path)) {
39      pageParams.page_size = 12
40    }
41    // 预览模式
42    if (this.ctx.query.preview) pageParams.preview = this.ctx.query.preview
43    // 获取当前页数据
44    const urlType = this.ctx.path.replace('.html', '').replace('/', '')
45    if (
46      globalThis.Server.checkDesign(this.ctx) &&
47      ['product-detail', 'article-detail', 'video-detail', 'store-detail'].includes(urlType)
48    ) {
49      this.pageData = localData[urlType]
50    } else {
51      if ((this.ctx.path.slice(-1) !== '/' && this.ctx.path.slice(-5) !== '.html') || this.ctx.state.remote_server){
52        this.pageData.page_type = '404'
53      } else {
54        this.pageData = await getPageData(this.ctx, pageParams)
55      }
56    }
57
58    this.pageData.page_category_id = this.pageData.category_id
59    this.pageData.url_path = url_path
60
61    if (this.pageData.page_category_id) {
62      const pageParams = {
63        language_code: this.getLanguageCode(),
64        site_id: this.ctx.state.site.site_id,
65        category_id: this.pageData.page_category_id
66      }
67
68      let categoryData = {}
69      let match_products = []
70      const urlType = this.ctx.path.replace('.html', '').replace('/', '')
71      if (
72        globalThis.Server.checkDesign(this.ctx) &&
73        ['product-detail', 'article-detail', 'video-detail'].includes(urlType)
74      ) {
75        categoryData = localData[urlType.replace('-detail', '') + '-page-category']
76        
77      } else {
78        this.ctx.state.page = this.pageData
79        categoryData = await getCategoryData(this.ctx, pageParams)
80        if (this.pageData.page_type === 'product_detail') {
81          match_products = this.pageData.content.is_match_product? (await getProductMatchData(this.ctx, { ...pageParams, product_id: this.pageData.content.id })) : []
82        }
83      }
84      this.pageData = setPageData(this.ctx, { ...categoryData, ...this.pageData, match_products })
85      if (!this.ctx.query.design && this.pageData.page_type === "landing_page" && categoryData.category.ad_permissions === 3) {
86        this.ctx.state.redirect(301, '/')
87      }
88    } else {
89      this.pageData = setPageData(this.ctx, this.pageData)
90    }
91
92    if (this.pageData.page_type === '404' && this.ctx.state.site.redirect_mode === 1) {
93      if (this.ctx.query.force && this.ctx.query.force === 'html') {
94        this.pageData.page_type = '301'
95      } else {
96        this.ctx.state.redirect(301, '/')
97      }
98    }
99
100    this.pageData.children = []
101    if (this.pageData.parents.length > 1) {
102      let pData = this.pageData.parents[1]
103      if (pData.id) this.pageData.children = [this.ctx.state.site.nav.find(p => p.id === pData.id)]
104    }
105
106    // 页面H1标签统计
107    this.pageData.h1_counter = 0
108
109    // allowAnimat
110    this.pageData.allowAnimat = checkAnimat(this.pageData.page_type)
111
112    // 优惠卷详情id
113    if (!this.pageData.content_id) this.pageData.content_id = getPageId(this.ctx.path)
114
115    // 分页
116    if (!this.pageData.page_number || this.pageData.page_number == 1) this.pageData.page_number = getPageNumber(this.ctx.path)
117    else if (this.pageData.page_number) this.pageData.page_number = parseInt(this.pageData.page_number)
118
119    // 初始获取友情链接数据
120    await this.initPartnerLink()
121    // 初始获取文档页面类型数据
122    await this.initDocument()
123
124    // 初始获取查找列表页面数据
125    await this.initPageListData()
126
127    // 检查站点TDK
128    this.checkTDK()
129    // 站点地图下,请求相关数据
130    if (['sitemap', 'sitemap_articles', 'sitemap_products', 'sitemap_videos', 'sitemap_derivative_products', 'sitemap_blogs', 'sitemap_topics_blogs', 'sitemap_tags', 'sitemap_faq'].includes(this.pageData.page_type)) {
131      if (this.ctx.state.remote_server){
132        this.pageData.page_type = '404'
133      } else {
134        await this.checkSiteMap()
135      }
136    }
137    this.initCanonicalHref()
138    this.initDetailsImg()
139    // this.initOgImage()
140    this.initDetailCssMode()
141    // this.pruneDetailHidesHtml()
142    return this.pageData
143  }
144
145  /**
146   * 清理三端隐藏的详情html
147   */
148  pruneDetailHidesHtml() {
149    if (globalThis.Server.checkDesign(this.ctx)) {
150      return;
151    }
152    const pageTypes = [
153      'product_detail', 'ai_product_detail', 'article_detail', 'video_detail'
154    ];
155    const that = this
156    if (pageTypes.includes(this.pageData.page_type)) {
157      /**
158       * @type {[{detail: [{description: *}]}]|*}
159       */
160      const arr = this.pageData.detail_description
161      if (Array.isArray(arr)) {
162        arr.forEach((sub, i) => {
163          const subArr = sub.detail
164          if (Array.isArray(subArr)) {
165            subArr.forEach((item, j) => {
166              if (item.description && typeof item.description === 'string') {
167                that.pageData.detail_description[i].detail[j].description = pruneHiddenHtml(item.description);
168              }
169            })
170          }
171        })
172      }
173    }
174  }
175  getLanguageCode() {
176    let languageCode = this.ctx.state.site.language_code
177    if (globalThis.Server.checkDesign(this.ctx)) {
178      const queryLanguageCode = globalThis.window.location.search.match(new RegExp("(\\?|&)language_code=([^&]*)(&|$)")) || []
179      languageCode = queryLanguageCode[2] || languageCode
180    }
181    return languageCode
182  }
183  initDetailCssMode() {
184    this.pageData.detailCssMode = [];
185    if (this.pageData.page_type === 'product_detail' || this.pageData.page_type === 'ai_product_detail' || this.pageData.page_type === 'article_detail' || this.pageData.page_type === 'video_detail') {
186      if (this.pageData.page_type === 'article_detail' || this.pageData.page_type === 'video_detail') {
187        this.pageData.detailCssMode.push(this.pageData.edit_mode || 1)
188      } else {
189        this.pageData.detail_description.forEach(item => {
190          item.detail.forEach(text => {
191            this.pageData.detailCssMode.push(text.edit_mode || 1)
192          })
193        })
194      }
195    } else if (checkDetail(this.pageData.page_type)) {
196      this.pageData.detailCssMode.push(2)
197    }
198    if (globalThis.Server.checkDesign(this.ctx) && this.pageData.detailCssMode[0]) { // 装修时,详情页加载可视化样式
199      // 装修模式下客户端赋值
200      let cssHref = ''
201      if (this.pageData.detailCssMode[0] === 1) {
202        cssHref = '//' + window.serverInfo.editorDomain + '/cloud-editor-responsive-out.css?v=4'
203      } else if (this.pageData.detailCssMode[0] === 2) {
204        if (typeof this.pageData.detail_css_name === 'string' && this.pageData.detail_css_name.length) {
205          cssHref = `/style/detail.css?unit=detail,${this.pageData.detail_css_name}`
206        }
207      }
208      document.querySelector('[style-mode="editor"]').setAttribute('href', cssHref)
209    }
210  }
211  /** 整理出详情中的img,并给没有alt的加上alt */
212  initDetailsImg() {
213    this.detail_images = []
214    // 遍历产品主图
215    this.pageData.album_list.forEach(item => {
216      this.detail_images.push(item.img)
217      item.alt = `${this.pageData.detail_title_text} ${this.detail_images.length}`
218    })
219    // 遍历html中的图片
220    this.pageData.detail_description.forEach(item => {
221      item.detail.forEach(text => {
222        text.description = text.description.replace(/<img.*?src=\"(.*?)\".*?>/g, (match, p1) => {
223          this.detail_images.push(p1)
224          if (match.indexOf(' alt=') > 0) {
225            if (/alt=("|')\s*("|')/.test(match)) { //如果为空,使用标题
226              let matchUrl = `${match.slice(0, 4)} ${match.slice(4)}`
227              matchUrl = matchUrl.replace(/alt=("|')\s*("|')/, `alt="${this.pageData.detail_title_text} ${this.detail_images.length}"`)
228              return matchUrl
229            } else { //或者使用自带的alt
230              return match
231            }
232          } else {
233            return `${match.slice(0, 4)} alt="${this.pageData.detail_title_text} ${this.detail_images.length}"${match.slice(4)}`
234          }
235        })
236      })
237    })
238  }
239  initOgImage() {
240    if (this.pageData.album_list && this.pageData.album_list[0] && this.pageData.album_list[0].img) {
241      this.pageData.og_image = this.pageData.album_list[0].img
242    } else if (this.detail_images.length > 0) {
243      this.pageData.og_image = this.detail_images[0]
244    } else {
245      this.pageData.og_image = this.ctx.state.site.logo_url
246    }
247  }
248  initCanonicalHref() {
249    if (!this.ctx.query.design) {
250      this.pageData.canonical_href = this.ctx.state.site.language_list
251        .find(p => p.code === this.ctx.state.site.language_code).href ||
252        `${this.ctx.state.site.protocol_domain}${calcPathName(this.ctx.path)}`
253    }
254  }
255  /**
256   * 如果是首页,TDK设置为站点的TDK
257   */
258  checkTDK() {
259    if (this.pageData.page_type === 'index') {
260      this.pageData.meta_keywords = this.ctx.state.site.meta_keywords
261      this.pageData.meta_description = this.ctx.state.site.meta_description
262      this.pageData.meta_title = this.ctx.state.site.meta_title
263    } else if (this.pageData.page_type === 'product_lives') {
264      this.pageData.meta_keywords = this.ctx.state.site.main_products
265      this.pageData.meta_description = this.ctx.state.site.company_name + ' ' + this.ctx.state.$t('Video Lists')
266      this.pageData.meta_title = this.ctx.state.site.company_name + ' ' + this.ctx.state.$t('Video Lists')
267    }
268  }
269  /**
270   * 如果是站点地图,请求相关数据
271   */
272  async checkSiteMap() {
273    // 修改--与sitemap相关的页面数据
274    this.pageData.sitemap = {}
275    const prefix = this.ctx.state.site.lang_prefix
276
277    // 根据路由参数获取当前页数
278    this.pageData.page_number = 1
279    if (/_list/.test(this.ctx.path)) {
280      let num = this.ctx.path.split('_list')[1]
281      if (Number(num.split('.')[0])) this.pageData.page_number = Number(num.split('.')[0])
282    }
283    // 以下接口基础参数
284    const base_params = {
285      language_code: this.ctx.state.site.language_code,
286      site_id: this.ctx.state.site.site_id,
287      page_size: 1000,
288      page_number: this.pageData.page_number
289    }
290
291    let res = { list: [] }
292    if ('sitemap' === this.pageData.page_type) {
293      // 获取栏目数据
294      res.product_category = await getPageCategoryList(this.ctx, {
295        language_code: this.ctx.state.site.language_code,
296        site_id: this.ctx.state.site.site_id,
297        relate_type: 2,
298        open_type: '1,2',
299        jump_url: ''
300      })
301      res.other_category = await getPageCategoryList(this.ctx, {
302        language_code: this.ctx.state.site.language_code,
303        site_id: this.ctx.state.site.site_id,
304        relate_type: '3,6,7,13,14,100,101',
305        open_type: '1,2',
306        jump_url: ''
307      })
308      this.pageData.page_title = this.ctx.state.$t('sitemap')
309
310    } else if ('sitemap_articles' === this.pageData.page_type) {
311      res = await getArticleListPageBySearch(this.ctx, {
312        ...base_params,
313        status: 1,
314        show_status: 1,
315        content_type: 3
316      })
317      this.pageData.page_title = this.ctx.state.$t('Articles Sitemap')
318
319    } else if ('sitemap_products' === this.pageData.page_type) {
320      res = await getProductListPageBySearch(this.ctx, {
321        ...base_params,
322        status: 1,
323        show_status: 1,
324        content_type: 2,
325        columns: 'title'
326      })
327      this.pageData.page_title = this.ctx.state.$t('Products Sitemap')
328
329    } else if ('sitemap_videos' === this.pageData.page_type) {
330      res = await getVideoListPageBySearch(this.ctx, {
331        ...base_params,
332        status: 1,
333        show_status: 1
334      })
335      this.pageData.page_title = this.ctx.state.$t('Videos Sitemap')
336
337    } else if ('sitemap_derivative_products' === this.pageData.page_type) {
338      res = await getProductListPageBySearch(this.ctx, {
339        ...base_params,
340        content_type: 4,
341        columns: 'title',
342        show_status: 1
343      })
344      this.pageData.page_title = this.ctx.state.$t('Derivative Products Sitemap')
345
346    } else if ('sitemap_blogs' === this.pageData.page_type) {
347      res = await getArticleListPageBySearch(this.ctx, {
348        ...base_params,
349        content_type: 5,
350        show_status: 1
351      })
352      this.pageData.page_title = this.ctx.state.$t('Derivative Blogs Sitemap')
353
354    } else if ('sitemap_topics_blogs' === this.pageData.page_type) {
355      res = await getPolymerizeList(this.ctx, {
356        ...base_params,
357        show_time_status: 2,
358        show_status: 1
359      })
360      this.pageData.page_title = this.ctx.state.$t('Topics Blogs Sitemap')
361    } else if ('sitemap_tags' === this.pageData.page_type) {
362      res = await getSitemapTagsList(this.ctx, base_params)
363      this.pageData.page_title = this.ctx.state.$t('Tags Sitemap')
364    } else if ('sitemap_faq' === this.pageData.page_type) {
365      res = await getFAQListPageBySearch(this.ctx, {
366        ...base_params,
367        show_status: 1
368      })
369      this.pageData.page_title = this.ctx.state.$t('Faq Sitemap')
370    }
371
372
373
374    if ('sitemap' !== this.pageData.page_type) {
375      this.pageData.page_count = res.page_count
376      this.pageData.page_total = res.total
377      this.pageData.page_size = base_params.page_size
378    }
379    this.pageData.meta_title = this.pageData.page_title + ' - ' + (this.ctx.state.site.company_brand_name || this.ctx.state.site.company_name_short || this.ctx.state.site.company_name)
380    this.pageData.meta_keywords = this.pageData.meta_title
381    this.pageData.meta_description = this.pageData.meta_title
382    this.pageData.page_base_url = `${prefix === '/' ? '' : prefix}/` + this.pageData.page_type
383    // 面包屑部分
384    this.pageData.parents = [
385      { href: '/', title: this.ctx.state.site.company_brand_name || this.ctx.state.site.company_name_short || this.ctx.state.site.company_name || this.ctx.state.$t('home') },
386      { href: '', title: this.pageData.page_title }
387    ]
388
389    res.count = await getContentCounts(this.ctx, {
390      site_id: this.ctx.state.site.site_id
391    })
392    this.pageData.sitemap = res
393  }
394
395  /**
396   * 获取友情链接
397   */
398  async initPartnerLink() {
399    const content = await getPartnerLink(this.ctx, { site_id: this.ctx.state.site.site_id, url_path: this.pageData.page_url })
400    let page_id = this.pageData.page_id || 0
401    this.pageData.partner_link = []
402    if (page_id || (!page_id && this.pageData.page_url === '/')) {
403      if (content.hasOwnProperty(page_id)) {
404        this.pageData.partner_link = content[page_id]
405      }
406    }
407  }
408
409  /**
410   * 初始化文档类型页面
411   */
412  async initDocument() {
413    //存在文档页面类型里面,隐私 privacy_policy    条款 terms_and_conditions
414    let page_url = ''
415    if (this.pageData.page_type === 'doc_privacy_policy') {
416      page_url = 'privacy_policy'
417    } else if (this.pageData.page_type === 'doc_terms_and_conditions') {
418      page_url = 'terms_and_conditions'
419    }
420    if (page_url) {
421      // 根据值value为页面类型去查找信息
422      const content = await getDocumentPage(this.ctx, { site_id: this.ctx.state.site.site_id, page_url })
423      if (!content || !content.status) {
424        this.pageData.page_type = '404'
425      } else {
426        if (page_url === 'privacy_policy') {
427          content.title = content.title || 'Privacy Policy'
428        }
429        this.pageData.meta_title = content.title
430        this.pageData.page_title = content.title
431        this.pageData.detail_title = content.title
432        this.pageData.detail_summary = content.description
433      }
434    }
435  }
436
437  /** 处理系统列表页数据和分页 */
438  initPageListData() {
439    switch (this.pageData.page_type) {
440      case 'product_list':
441        // 更多热门产品
442        if (this.ctx.state.site.template_type === 'b2b') return
443        return this.initPageListDataBySearch({ sort: this.pageData.page_sort_type })
444      case 'more_best_selle':
445        // 更多热卖产品
446        return this.initPageListDataBySearch({ is_hot: 1 })
447      case 'more_new_products':
448        // 更多最新产品
449        return this.initPageListDataBySearch({ is_new: 1 })
450      case 'more_recommend':
451        // 更多推荐产品
452        return this.initPageListDataBySearch({ is_recommend: 1 })
453      case 'coupon_detail':
454        // 优惠卷可用商品
455        return this.initPageListDataBySearch({ coupon_ids: `${this.pageData.content_id}` })
456      case 'reduction_detail':
457        // 满减产品
458        return this.initPageListDataBySearch({ reduction_ids: `${this.pageData.content_id}` })
459      // case 'faq_list':
460      //   // faq列表页
461      //   return this.initPageListForFAQ()
462    }
463  }
464  /** 获取列表页数据-Search */
465  async initPageListDataBySearch(params = {}) {
466    params.language_code = this.ctx.state.site.language_code
467    params.site_id = this.ctx.state.site.site_id
468    params.page_number = this.pageData.page_number
469    params.page_size = this.pageData.page_size <= 0 ? 12 : this.pageData.page_size
470    params.columns = 'title,summary,subtitle' + (this.ctx.state.site.is_shop ? ',price,discount,reduction' : '')
471    if (this.pageData.page_category_id) params.page_category_id = this.pageData.page_category_id
472    if (globalThis.Server.checkDesign(this.ctx)) {
473      const queryLanguageCode = globalThis.window.location.search.match(new RegExp("(\\?|&)language_code=([^&]*)(&|$)")) || []
474      params.language_code = queryLanguageCode[2] || params.language_code
475    }
476    const res = await getProductListPageBySearch(this.ctx, params)
477
478    this.setPageListData({
479      list: new globalThis.Server.ContentList().product(res.list),
480      page_count: res.page_number > res.page_count ? 0 : res.page_count,
481      page_base_url: getBasePagePath(this.ctx.path),
482      page_number: res.page_number,
483      page_total: res.total
484    })
485  }
486  /* 获取faq列表页数据  */
487  async initPageListForFAQ(params = {}) {
488    params = {
489      language_code: this.ctx.state.site.language_code,
490      site_id: this.ctx.state.site.site_id,
491      page_number: this.pageData.page_number,
492      page_size: this.pageData.page_size <= 0 ? 12 : this.pageData.page_size,
493      ...params
494    }
495    const res = await getFAQListPageBySearch(this.ctx, params)
496    
497    this.setPageListData({
498      list: new globalThis.Server.ContentList().default(res.list),
499      page_count: res.page_number > res.page_count ? 0 : res.page_count,
500      page_base_url: getBasePagePath(this.ctx.path),
501      page_number: res.page_number,
502      page_total: res.total
503    })
504  }
505  /** 设置列表页数据 */
506  setPageListData({ list, page_count, page_base_url, page_number, page_size, page_total }) {
507    this.pageData.list = list || this.pageData.list
508    this.pageData.page_count = page_count || this.pageData.page_count
509    this.pageData.page_base_url = page_base_url || this.pageData.page_base_url
510    //加上小语种前缀
511    this.pageData.page_number = page_number || this.pageData.page_number
512    this.pageData.page_size = page_size || this.pageData.page_size
513    this.pageData.page_total = page_total || this.pageData.page_total
514  }
515
516  /** 单例模式 */
517  static getInstance() {
518    if (!this.instance) return this.instance = new Page()
519    return this.instance
520  }
521}
522
523export default Page

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.