list.vue 7.86 KB
<template>
  <div>
    <LayoutApp :show-back="true" :title="title">
      <div class="filter">
        <div class="filter-tab">
          <div class="tab-item" :class="selectedType === 2 && 'selected-tab'" @click="pressType(2)">人气</div>
          <div class="tab-item middle" :class="selectedType === 1 && 'selected-tab'" @click="pressType(1)">
            <span>价格</span>
            <div :class="arrowImage"></div>
          </div>
          <div class="tab-item" :class="selectedType === 3 && 'selected-tab'" @click="pressType(3)">新品</div>
        </div>
        <div class="middle">
          <div class="screen middle" @click="goFilter()">
            <div class="screen-img"></div>
            筛选
          </div>
          <div class="search-img" @click="goSearch()"></div>
        </div>
      </div>
      <Scroll class="product-list" v-show="!productList.isEmpty"
              :options="scrollOptions"
              :data="productList.list"
              @pulling-up="onPullingUp">
        <ProductList :list="productList.list"></ProductList>
      </Scroll>
      <EmptyList class="empty-wrapper product-list" :tip="`暂无数据`" v-show="productList.isEmpty" >
      </EmptyList>
    </LayoutApp>
    <Filtrate ref="filtrate"></Filtrate>
  </div>
</template>
<script>
import ProductList from './components/productList';
import Filtrate from './filtrate';
import EmptyList from '../../components/ufo-no-item';

import {Scroll} from 'cube-ui';
import {mapState, createNamespacedHelpers} from 'vuex';

const {mapActions} = createNamespacedHelpers('list');

export default {
  name: 'List',
  components: {
    ProductList,
    Scroll,
    Filtrate,
    EmptyList
  },
  data() {
    return {
      scrollOptions: {
        bounce: {
          top: false
        },
        pullUpLoad: true
      },
      fixed: false,
      selectedType: 2, // tab类型高亮
      priceDesc: true,
      arrowImage: '',
      title: '',
      productList: {
        showErrorPage: false,
        isFetching: false,
        error: null,
        page: 0, // 当前页
        page_size: 10, // 每页数量
        page_total: 0, // 总共多少页
        total: 0, // 总共多少条
        endReached: false, // 到达底部
        list: [], // 商品列表
        isEmpty: false,
      },
      searchParams: {
        type: 0, // type:0,推荐;1,热销;2,即将发售; 3,品类; 4,品牌;5,系列;6,搜索 7, 收藏
        order: '', // 指定排序
        productPool: null, // 商品池id
        sort: null, // 品类id
        brand: null, // 品牌id
        series: null, // 系列id
        gender: null, // 性别
        size: null, // 尺码id
        isSoonSale: null, // 是否是即将售卖
        query: null, // 搜索词
        limit: null, // 每页记录数
        page: null, // 当前页号
        coupon_token: null, // 优惠券token
      },
    };
  },
  activated: function() {
    if (this.yoho.direction === 'forword') {
      this.$refs.filtrate.hide();
      Object.assign(this.$data, this.$options.data());
    }
    this.changeArrow();
    let params = {...this.$route.query};

    if (params.title) {
      this.title = params.title;
      delete params.title;
    } else {
      this.title = '商品列表';
    }
    !params.order && (params.order = 'sale_desc');
    this.fetchList({...params, isReset: true});
  },

  computed: {
    ...mapState(['yoho'])
  },

  methods: {
    ...mapActions(['fetchProductList', 'getDirection']),

    // 上拉加载
    async onPullingUp() {
      await this.fetchList();
    },

    // 查询商品列表
    fetchList: async function(params) {
      let searchParams = this.searchParams;
      let list = this.productList;
      let pageSize = list.page_size;
      let isReset = false;

      if (params && params.isReset) {
        isReset = true;
        delete params.isReset;
      }

      if (!isReset && (list.endReached || (!list.endReached && list.page_total === 1))) {
        return;
      }
      if (typeof params === 'object' && Object.keys(params)) {
        searchParams = Object.assign({...searchParams}, params);
        this.searchParams = searchParams;
      }

      let page = isReset ? 1 : (list.page + 1);

      for (let key in searchParams) {
        if (!searchParams[key]) {
          delete searchParams[key];
        }
      }
      let result = await this.fetchProductList({
        ...searchParams,
        page,
        pageSize
      });
      let {data} = result;

      if (result.code === 200) {

        data.endReached = (data.page === data.page_total) && (data.page_size !== 1) || !data.page_total;
      }

      if (typeof data === 'object' && Object.keys(data).length) {
        for (let key in data) {
          if (key === 'product_list') {
            list.list = data.page > 1 ? list.list.concat(data.product_list) : data.product_list;
          } else {
            list[key] = data[key];
          }
        }

        list.list && list.list.length ? list.isEmpty = false : list.isEmpty = true;

        this.productList = list;
      }
    },

    // 点击tab flag, 0: 推荐, 1: 价格, 2: 人气, 3: 新品
    pressType(flag) {
      if (flag === this.selectedType && flag !== 1) {
        return;
      }
      let filterParams = this.$refs.filtrate.getParams();
      let {sort} = this.searchParams;
      let params = {
        sort: filterParams.sort.join(',') || sort,
        brand: filterParams.brand.join(','), // 品牌id
        gender: filterParams.gender.join(','), // 性别
        size: filterParams.size.join(','), // 尺码id
      };

      this.selectedType = flag;
      if (flag === 1) {
        this.priceDesc = !this.priceDesc;
        params.order = this.priceDesc ? 'p_desc' : 'p_asc';
      } else if (flag === 2) {
        this.priceDesc = true;
        params.order = 'sale_desc';
      } else if (flag === 3) {
        this.priceDesc = true;
        params.order = 'st_desc';
      }
      params.isReset = true;
      this.fetchList(params);
      this.changeArrow();
    },
    goSearch() {
      this.$router.push({
        name: 'Search',
      });
    },
    changeArrow() {
      this.arrowImage = (this.selectedType === 3 || this.selectedType === 2) ? 'price-arrow' :
        this.priceDesc ? 'desc-arrow' : 'asc-arrow';
    },
    goFilter() {
      this.$refs.filtrate.show();
    }
  }
};
</script>

<style scoped>
  .filter {
    display: flex;
    height: 120px;
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
    padding-left: 42px;
    padding-right: 38px;
    z-index: 999;
    background: #fff;
    position: relative;
  }

  .filter-tab {
    display: flex;
    flex-direction: row;
    align-items: center;
    font-size: 32px;
    color: #999;
    text-align: center;
  }

  .selected-tab {
    color: #000;
    font-weight: bold;
  }

  .tab-item {
    margin-right: 60px;
  }

  .screen {
    font-size: 32px;
    color: #000;
    letter-spacing: 0;
    margin-right: 24px;
  }

  .middle {
    display: flex;
    align-items: center;
  }

  .asc-arrow {
    width: 40px;
    height: 40px;
    background: url(~statics/image/list/asc_arrow@3x.png) no-repeat;
    background-size: cover;
  }

  .desc-arrow {
    width: 40px;
    height: 40px;
    background: url(~statics/image/list/desc_arrow@3x.png) no-repeat;
    background-size: cover;
  }

  .price-arrow {
    width: 40px;
    height: 40px;
    background: url(~statics/image/list/price_arrow@3x.png) no-repeat;
    background-size: cover;
  }

  .screen-img {
    width: 40px;
    height: 40px;
    background: url(~statics/image/list/filter@3x.png) no-repeat;
    background-size: cover;
  }

  .product-list {
    background: #f5f5f5;
  }

  .search-img {
    width: 40px;
    height: 40px;
    margin-left: 20px;
    background: url(~statics/image/list/search_icon@3x.png) no-repeat;
    background-size: cover;
  }

  .empty-wrapper {
    margin: auto 0;
    position: absolute;
    top: 0;
    bottom: 0;
  }
</style>