list.vue 10.4 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" @click="pressType(1)">
            <span :class="selectedType === 1 && 'selected-tab'">价格</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 ref="scroll" class="product-list" v-show="!productList.isEmpty"
              :scroll-events="['scroll-end']"
              :options="scrollOptions"
              :data="productList.list"
              @scroll-end="scrollHandler"
              @pulling-up="onPullingUp">
        <ProductList ref="product" :list="productList.list" :yasParams="yasParams"></ProductList>
      </Scroll>
      <EmptyList class="empty-wrapper product-list" :tip="`暂无数据`" v-show="productList.isEmpty">
      </EmptyList>
    </LayoutApp>
    <Filtrate ref="filtrate" :yasParams="yasParams"></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: function() {
    return {
      scrollOptions: {
        bounce: {
          top: false
        },
        pullUpLoad: true,
        pullDownRefresh: false,
        useTransition: false,
      },
      fixed: false,
      selectedType: 2, // tab类型高亮
      priceDesc: true,
      arrowImage: '',
      title: '',
      yasParams: {P_NAME: 'XY_UFOSearchList', TYPE_ID: 1},
      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: async 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 = '商品列表';
    }
    this.setYasParam({param: params, tab: {index: 1, name: '人气'}});
    !params.order && (params.order = 'sale_desc');
    await this.fetchList({...params, isReset: true});
    this.yasShowPage();
  },

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

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

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

    scrollHandler({y}) {
      let height = -y;

      this.$refs.product.yasShowEvent(height);
    },

    // 查询商品列表
    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: 新品
    async 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.setYasParam({tab: {index: 2, name: '价格'}});
        this.priceDesc = !this.priceDesc;
        params.order = this.priceDesc ? 'availableNowPrice:asc' : 'availableNowPrice:desc';
      } else if (flag === 2) {
        this.setYasParam({tab: {index: 1, name: '人气'}});
        this.priceDesc = true;
        params.order = 'sale_desc';
      } else if (flag === 3) {
        this.setYasParam({tab: {index: 3, name: '新品'}});
        this.priceDesc = true;
        params.order = 'st_desc';
      }
      params.isReset = true;
      await this.fetchList(params);
      this.$refs.scroll.scrollTo(0, 0, 300);
      this.changeArrow();
      this.yasShowPage();
      this.yasTab();
    },
    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();
    },
    setYasParam: function({param, tab}) {
      if (param && typeof param === 'object' && Object.keys(param).length) {
        let P_NAME = 'XY_UFOSearchList', TYPE_ID = 1, P_PARAM = [];

        for (let key in param) {
          if (key === 'brand' && param[key] && param.type !== 6) {
            P_NAME = 'XY_UFOBrandList';
            TYPE_ID = 3;
          }
          if (key === 'series' && param[key] && param.type !== 6) {
            P_NAME = 'XY_UFOSeriesList';
            TYPE_ID = 2;
          }
          if (key === 'productPool' && param[key] && param.type !== 6) {
            P_NAME = 'XY_UFOProductPoolList';
            TYPE_ID = 4;
          }
          if (!param[key]) {
            delete param[key];
          }
          P_PARAM.push(param[key]);
        }
        Object.assign(this.yasParams, {
          P_NAME,
          P_PARAM: P_PARAM.toString(),
          TYPE_ID,
          TAB_ID: this.tabIndex || '',
          TAB_NAME: this.tabName || ''
        });
      }

      if (tab && typeof tab === 'object' && Object.keys(tab).length) {
        this.yasParams.TAB_ID = tab.index;
        this.yasParams.TAB_NAME = tab.name;
      }
    },
    yasShowPage() {
      let {total, list} = this.productList;
      let PRD_LIST = [];

      for (let item of list) {
        PRD_LIST.push(item.id);
      }
      PRD_LIST = PRD_LIST.toString();
      this.$store.dispatch('reportYas', {
        params: {
          param: {...this.yasParams, TOTAL: total, PRD_LIST},
          appop: 'XY_UFO_PRD_LIST_L'
        }
      });
    },
    yasTab() {
      this.$store.dispatch('reportYas', {
        params: {
          param: {...this.yasParams},
          appop: 'XY_UFO_PRD_LIST_TAB_C'
        }
      });
    }
  }
};
</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>