search.vue 12.5 KB
<!--
 * @Date: 2024-10-20 16:57:48
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2024-12-12 14:54:04
 * @FilePath: /hager/src/views/search.vue
 * @Description: 文件描述
-->
<template>
  <div class="hager-search-page">
    <hager-box>
      <div class="search-title">与“{{ keyword }}”相关的搜索结果</div>
      <el-tabs v-model="activeName" @tab-click="handleClick">
        <el-tab-pane name="product">
          <div slot="label" class="customer-label">产品&nbsp;&nbsp;<span>{{ count_product }}</span></div>
          <div class="search-product-list">
            <div :class="['search-product-item', is_xs ? 'xs' : '']" v-for="(item, index) in product_list" :key="index">
              <div @click="goToDetail(item)" :class="['search-product-item-img', is_xs ? 'xs' : '']" :style="{ 'background-image': 'url('+ item.cover +')' }">
              <!-- <div :class="['search-product-item-img', is_xs ? 'xs' : '']"> -->
                <!-- <img style="width: 100%; height: auto;" :src="item.cover"> -->
              </div>
              <p @click="goToDetail(item)" class="search-product-item-title">{{ item.product_name }}</p>
            </div>
          </div>
          <div style="height: 5rem;"></div>
        </el-tab-pane>
        <el-tab-pane name="solution">
          <div slot="label" class="customer-label">解决方案&nbsp;&nbsp;<span>{{ count_solution }}</span></div>
          <div style="margin-top: 1rem;" v-for="(item, index) in solution_list" :key="index">
            <el-breadcrumb separator="/">
              <el-breadcrumb-item>首页</el-breadcrumb-item>
              <el-breadcrumb-item>解决方案</el-breadcrumb-item>
            </el-breadcrumb>
            <div :class="['search-news-wrapper', is_xs ? 'xs' : '']">
              <div class="search-news-title" v-html="highlightKeyword(keyword, item.solution_name)"></div>
              <div class="search-news-content" v-html="highlightKeyword(keyword, item.solution_description)"></div>
              <div class="search-news-more">
                <div class="search-news-more-btn" @click="goToCase(item.id)">MORE</div>
              </div>
            </div>
          </div>
        </el-tab-pane>
        <el-tab-pane name="case">
          <div slot="label" class="customer-label">成功案例&nbsp;&nbsp;<span>{{ count_case }}</span></div>
          <div style="margin-top: 1rem;" v-for="(item, index) in case_list" :key="index">
            <div :class="['search-news-wrapper', is_xs ? 'xs' : '']">
              <div class="search-news-title" v-html="highlightKeyword(keyword, item.post_title)"></div>
              <div class="search-news-content" v-html="highlightKeyword(keyword, item.post_description)"></div>
              <div class="search-news-more">
                <div class="search-news-more-btn" @click="goToSuccess(item.id)">MORE</div>
              </div>
            </div>
          </div>
        </el-tab-pane>
        <el-tab-pane name="news">
          <div slot="label" class="customer-label">新闻&nbsp;&nbsp;<span>{{ count_news }}</span></div>
          <div style="margin-top: 1rem;" v-for="(item, index) in news_list" :key="index">
            <el-breadcrumb separator="/">
              <el-breadcrumb-item>首页</el-breadcrumb-item>
              <el-breadcrumb-item>新闻中心</el-breadcrumb-item>
            </el-breadcrumb>
            <div :class="['search-news-wrapper', is_xs ? 'xs' : '']">
              <div class="search-news-title" v-html="highlightKeyword(keyword, item.post_title)"></div>
              <div class="search-news-content" v-html="highlightKeyword(keyword, item.post_excerpt)"></div>
              <div class="search-news-more">
                <div class="search-news-more-btn" @click="goToNews(item.id)">MORE</div>
              </div>
            </div>
          </div>
        </el-tab-pane>
      </el-tabs>
    </hager-box>
    <hager-box v-if="activeName === 'news'">
      <hager-load-more v-if="news_page < news_max_page" @click.native="getMore"></hager-load-more>
    </hager-box>
    <hager-box v-if="activeName === 'case'">
      <hager-load-more v-if="case_page < case_max_page" @click.native="getMore"></hager-load-more>
    </hager-box>
  </div>
</template>

<script>
import mixin from 'common/mixin';
import hagerBox from '@/components/common/hagerBox';
import $ from 'jquery';
import objectFitImages from 'object-fit-images';
import { searchAPI } from '@/api/hager';
import hagerLoadMore from '@/components/hagerLoadMore.vue';

export default {
  components: { hagerBox },
  mixins: [mixin.init],
  data () {
    return {
      activeName: 'product',
      keyword: this.$route.params.keyword,
      news_list: [],
      case_list: [],
      count_news: 0,
      count_case: 0,
      count_product: 0,
      count_solution: 0,
      product_list: [],
      solution_list: [],
      news_page: 1,
      case_page: 1,
      limit: 10,
      news_max_page: 0,
      case_max_page: 0,
      no_product_img: 'https://cdn.ipadbiz.cn/hager/img/no-product-img.png',
    }
  },
  watch: {
    '$route.params.keyword': function(newKeyword, oldKeyword) {
      this.keyword = newKeyword || '';
      if (newKeyword !== oldKeyword) { // 关键词变化时,重新搜索
        this.activeName = 'product';
        // 获取默认列表
        this.getList();
      }
    },
  },
  async mounted () {
    // 获取默认列表
    this.getList();
    //
    objectFitImages(this.$el); // 对当前组件的 DOM 元素应用
    if (this.is_xs) { // 自适应模式下,左右箭头的颜色修改
      this.modifyTabColor();
    }
    // 监听窗口的 resize 事件
    window.addEventListener('resize', this.modifyTabColor);
  },
  beforeDestroy() {
    // 在组件销毁前移除监听器,防止内存泄漏
    window.removeEventListener('resize', this.modifyTabColor);
  },
  methods: {
    modifyTabColor () { // 调整Tab箭头颜色
      this.$nextTick(() => {
        setTimeout(() => {
          // next按钮修改颜色
          $('.el-tabs__nav-wrap').children('span.el-tabs__nav-next').css('color', '#F56400');
          $('.el-tabs__nav-wrap').children('span.el-tabs__nav-next').on('click', (e) => {
            $('.el-tabs__nav-wrap').children('span.el-tabs__nav-next').css('color', '#333')
            $('.el-tabs__nav-wrap').children('span.el-tabs__nav-prev').css('color', '#F56400')
          })
          $('.el-tabs__nav-wrap').children('span.el-tabs__nav-prev').on('click', (e) => {
            $('.el-tabs__nav-wrap').children('span.el-tabs__nav-next').css('color', '#F56400')
            $('.el-tabs__nav-wrap').children('span.el-tabs__nav-prev').css('color', '#333')
          })
        }, 100);
      })
    },
    async getList () { // 获取默认列表数据
      const { code, data } = await searchAPI({ keyword: this.keyword });
      if (code) {
        //
        this.count_news = data.count_news;
        this.count_case = data.count_case;
        this.count_product = data.count_product;
        this.count_solution = data.count_solution;
        //
        this.product_list = data.product;
        // 新增不可用状态的图片
        this.product_list.forEach(item => {
          if (item.product_status === 'apply') {
            item.cover = this.no_product_img
          }
        })
        this.solution_list = data.solution;
      }
    },
    async getNewsList (type = '', page) { // 获取新闻列表数据
      const { code, data } = await searchAPI({ keyword: this.keyword, type, page, limit: this.limit });
      if (code) {
        this.news_list = data.list;
        this.news_max_page = data.max_page;
      }
    },
    async getCaseList (type = '', page) { // 获取成功案例列表数据
      const { code, data } = await searchAPI({ keyword: this.keyword, type, page, limit: this.limit });
      if (code) {
        this.case_list = data.list;
        this.case_max_page = data.max_page;
      }
    },
    async getMoreNewsList (type = '', page) {
      const { code, data } = await searchAPI({ keyword: this.keyword, type, page, limit: this.limit });
      if (code) {
        this.news_list = this.news_list.concat(data.list);
      }
    },
    async getMoreCaseList (type = '', page) {
      const { code, data } = await searchAPI({ keyword: this.keyword, type, page, limit: this.limit });
      if (code) {
        this.case_list = this.case_list.concat(data.list);
      }
    },
    handleClick(tab, event) {
      switch (tab.name) {
        case 'product':
          this.getList();
          break;
        case 'solution':
          this.getList();
          break;
        case 'case':
          this.case_page = 1;
          this.case_max_page = 0;
          this.getCaseList(tab.name, this.case_page);
          break;
        case 'news':
          this.news_page = 1;
          this.news_max_page = 0;
          this.getNewsList(tab.name, this.news_page);
          break;
      }

    },
    getMore () {
      if (this.activeName === 'case') {
        this.case_page += 1;
        this.getMoreCaseList(this.activeName, this.case_page);
      }
      if (this.activeName === 'news') {
        this.news_page += 1;
        this.getMoreNewsList(this.activeName, this.news_page);
      }
    },
    highlightKeyword (keyword, text) {
      // 创建一个正则表达式来查找关键词
      var regex = new RegExp(`(${keyword})`, 'gi');

      // 用 <span> 标签替换匹配到的关键词并加上高亮类
      var highlightedText = text?.replace(regex, '<span style="color: #00ABE5;">$1</span>');

      return highlightedText;
    },
    goToNews (id) {
      this.$router.push({
        path: `/news/detail/${id}`,
      });
    },
    goToDetail (v) { // 跳转产品详情
      this.$router.push({
        path: `/product/detail/${v.id}/${v.category_id}/${Date.now()}`,
      });
    },
    goToCase (id) {
      this.$router.push({
        path: `/solution/detail/${id}/${Date.now()}`,
      });
    },
    goToSolution (v) { // 跳转产品详情
      this.$router.push({
        path: `/product/detail/${v.id}`,
      });
    },
    goToSuccess (v) { // 跳转成功案例
      this.$router.push({
        path: `/solution/case/${v}}`,
      });
    }
  }
}
</script>

<style lang="less" scoped>
  .hager-search-page {
    .search-title {
      font-size: 1.25rem;
      color: @secondary-color;
      margin: 2rem 0;
      font-weight: bold;
    }

    .search-product-list {
      display: flex;
      flex-wrap: wrap;
      gap: 1rem;
      margin-top: 1rem;
    }
    .search-product-item {
      width: calc(25.25% - 1rem);
      &.xs {
        width: calc(50% - 1rem);
      }
    }
    .search-product-item-img {
      background-color: #FFF;
      display: flex;
      align-items: center;
      justify-content: center;
      height: 18rem;
      padding: 3rem;
      box-sizing: border-box;
      border-radius: 5px;
      border: 1px solid #ECECEC;
      background-position: center;
      background-size: 50%;
      background-repeat: no-repeat;
      &.xs {
        padding: 3rem 1rem;
        background-size: 80%;
        img {
          width: 100%;
        }
      }

      &:hover {
        cursor: pointer;
      }
    }
    .search-product-item-title {
      text-align: left;
      margin-top: 0.75rem;
      color: @text-color;
      padding-left: 0.5rem;
      font-weight: bold;
      &:hover {
        cursor: pointer;
        text-decoration: underline;
      }
    }

    .search-news-wrapper {
      margin: 1.5rem 0;
      border-bottom: 1px solid #ECECEC;
      &.xs {
      }
      .search-news-title {
        font-size: 1.15rem;
        font-weight: bold;
        margin-bottom: 1rem;
      }
      .search-news-content {
        line-height: 2rem;
      }
      .search-news-more {
        display: flex;
        justify-content: flex-end;
        .search-news-more-btn {
          color: #F56400;
          padding: 0.5rem 2rem;
          border: 1px solid #F56400;
          background-color: #FFF;
          margin: 1rem 0;
          transition: color 0.25s ease-in-out, background-color 0.25s ease-in-out;
          &:hover {
            color: #FFF;
            background-color: #F56400;
            cursor: pointer;
          }
        }
      }
    }
  }

  :deep(.el-tabs__item.is-active, ) {
    color: @secondary-color;
  }

  :deep(.el-tabs__active-bar) {
    background-color: @secondary-color;
  }

  :deep(.el-tabs__item:hover) {
    color: @secondary-color;
  }

  :deep(.el-tabs__item) {
    color: @text-color;
  }

  .customer-label {
    font-size: 0.95rem;
    padding: 0 0.5rem;
    span {
      color: #F56400;
    }
  }

  :deep(.el-tabs__nav-prev) {
    font-size: 1rem;
  }
  :deep(.el-tabs__nav-next) {
    font-size: 1rem;
  }
</style>