255 lines
7.9 KiB
Vue
255 lines
7.9 KiB
Vue
<template>
|
||
<view>
|
||
<u-navbar :border-bottom="false" :is-back="false" :background="{ background: '#ffffff' }">
|
||
<view class="pl-base w-full" @tap="$u.route('/pages/search/search')">
|
||
<u-search disabled placeholder="搜索商品名称" :show-action="false"></u-search>
|
||
</view>
|
||
<template #right>
|
||
<view class="mx-base relative" @tap="$u.routeAuth('/pageA/news/index')">
|
||
<u-icon name="chat" size="48"></u-icon>
|
||
<block v-if="news_num > 0">
|
||
<u-badge :is-dot="true" size="16" :offset="[0, 2]" class="badge"></u-badge>
|
||
</block>
|
||
</view>
|
||
</template>
|
||
</u-navbar>
|
||
<view class="rounded-b-md bg-white fixed top-0 left-0 w-full z-50">
|
||
<view class="w-full" :style="[{ height: StatusBar + 44 + 'px' }]"></view>
|
||
<u-tabs
|
||
class="cu-tabs w-full"
|
||
active-color="#378264"
|
||
inactive-color="#808080"
|
||
height="60"
|
||
bar-height="8"
|
||
:list="tabsList"
|
||
:is-scroll="true"
|
||
:current="tabsCurrent"
|
||
@change="tabChange"
|
||
></u-tabs>
|
||
<view class="h-80rpx flex justify-between items-center px-40rpx">
|
||
<view class="text-txGray text-lg" :class="filterSort == '' ? 'text-primary' : ''" @tap="onChangeFilter('')">综合 </view>
|
||
<view
|
||
class="text-txGray text-lg flex items-center"
|
||
:class="filterSort == 'price' || filterSort == '-price' ? 'text-primary' : ''"
|
||
@tap="onPriceSort"
|
||
>
|
||
<text> 价格 </text>
|
||
<view>
|
||
<trigonometry :key="'a' + key" direction="up" :color="filterSort == 'price' ? '#378264' : '#808080'"> </trigonometry>
|
||
<trigonometry :key="'b' + key" direction="down" :color="filterSort == '-price' ? '#378264' : '#808080'"> </trigonometry>
|
||
</view>
|
||
</view>
|
||
<view
|
||
class="text-txGray text-lg flex items-center"
|
||
:class="filterSort == 'sales' || filterSort == '-sales' ? 'text-primary' : ''"
|
||
@tap="onSaleSort"
|
||
>
|
||
<text> 销量 </text>
|
||
<view>
|
||
<trigonometry :key="'c' + key" direction="up" :color="filterSort == 'sales' ? '#378264' : '#808080'"> </trigonometry>
|
||
<trigonometry :key="'d' + key" direction="down" :color="filterSort == '-sales' ? '#378264' : '#808080'"> </trigonometry>
|
||
</view>
|
||
</view>
|
||
<view class="text-txGray text-lg" :class="filterSort == 'release_at' ? 'text-primary' : ''" @tap="onChangeFilter('release_at')">上新</view>
|
||
</view>
|
||
</view>
|
||
|
||
<mescroll-body
|
||
:height="height"
|
||
:bottombar="false"
|
||
ref="mescrollRef"
|
||
@init="mescrollInit"
|
||
@down="downCallback"
|
||
@up="upCallback"
|
||
:down="downOption"
|
||
:up="upOption"
|
||
>
|
||
<view class="px-rowSm mt-20rpx pt-base" :style="[{ marginTop: 150 + 'rpx' }]">
|
||
<!-- <view class="grid grid-cols-2 gap-x-10rpx px-10rpx gap-y-20rpx">
|
||
<goods-item v-for="(item, index) in goods" :goods="item" :key="index"></goods-item>
|
||
</view> -->
|
||
<goods-list ref="uWaterfall" :list="goods"></goods-list>
|
||
</view>
|
||
</mescroll-body>
|
||
</view>
|
||
</template>
|
||
<script>
|
||
import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js';
|
||
import CartMixin from '@/pages/shop_cart/mixin';
|
||
export default {
|
||
mixins: [MescrollMixin, CartMixin],
|
||
data() {
|
||
return {
|
||
key: 0,
|
||
firstLoading: true,
|
||
tabsCurrent: 0,
|
||
tabsList: [],
|
||
filter: {
|
||
sort: '', //排序:price 价格,sales 销量,release_at 上架时间。示例:price 按价格升序,-price 按价格降序
|
||
},
|
||
downOption: {
|
||
// use: false,
|
||
},
|
||
upOption: {
|
||
auto: false,
|
||
},
|
||
};
|
||
},
|
||
computed: {
|
||
StatusBar() {
|
||
const { statusBarHeight } = this.$u.sys();
|
||
return statusBarHeight;
|
||
},
|
||
filterSort() {
|
||
return this.filter.sort;
|
||
},
|
||
goods() {
|
||
return this.tabsList[this.tabsCurrent]?.goods ?? [];
|
||
},
|
||
height() {
|
||
const { windowHeight, statusBarHeight } = this.$u.sys();
|
||
return windowHeight - statusBarHeight - 44 + 'px';
|
||
},
|
||
},
|
||
onShow() {
|
||
const params = uni.getStorageSync('/pages/sort/index') ?? '';
|
||
uni.removeStorageSync('/pages/sort/index');
|
||
this.id = params.id;
|
||
if (!!this.id && this.tabsList.length > 0) {
|
||
const index = this.tabsList?.findIndex(({ id }) => id == this.id);
|
||
if (index != this.tabsCurrent) {
|
||
setTimeout(()=>{
|
||
this.tabChange(index >= 0 ? index : 0);
|
||
},200)
|
||
}
|
||
}
|
||
},
|
||
methods: {
|
||
async downCallback() {
|
||
this.mescroll.resetUpScroll();
|
||
},
|
||
async upCallback(page) {
|
||
if (this.firstLoading) {
|
||
await this.getCategories();
|
||
}
|
||
this.getGoodsList(page);
|
||
this.firstLoading = false;
|
||
},
|
||
//改变筛选条件
|
||
onChangeFilter(type) {
|
||
if (type == this.filter.sort) return;
|
||
this.$u.throttle(() => {
|
||
this.$refs.uWaterfall.clear();
|
||
this.$nextTick(() => {
|
||
this.filter.sort = type;
|
||
this.mescroll.resetUpScroll();
|
||
});
|
||
});
|
||
},
|
||
//价格排序
|
||
onPriceSort() {
|
||
this.Refresh();
|
||
const type = this.filter.sort == 'price' ? '-price' : 'price';
|
||
this.onChangeFilter(type);
|
||
},
|
||
//销量排序
|
||
onSaleSort() {
|
||
this.Refresh();
|
||
const type = this.filter.sort == 'sales' ? '-sales' : 'sales';
|
||
this.onChangeFilter(type);
|
||
},
|
||
//刷新子组件
|
||
Refresh() {
|
||
this.$nextTick(() => {
|
||
this.key++;
|
||
});
|
||
},
|
||
// 切换
|
||
tabChange(index) {
|
||
this.filter.sort = '';
|
||
if (!this.tabsCurrent) this.tabsCurrent = 0;
|
||
|
||
this.$refs.uWaterfall.clear();
|
||
|
||
this.$nextTick(() => {
|
||
console.log("=======");
|
||
console.log(index);
|
||
let preTab = this.tabsList[this.tabsCurrent];
|
||
preTab.y = this.mescroll.getScrollTop();
|
||
this.tabsCurrent = index;
|
||
|
||
const curTab = this.tabsList[index];
|
||
if (!curTab.goods) {
|
||
this.mescroll.resetUpScroll();
|
||
} else {
|
||
this.mescroll.setPageNum(curTab.num + 1);
|
||
this.mescroll.endSuccess(curTab.curPageLen, curTab.hasNext);
|
||
this.$nextTick(() => {
|
||
this.mescroll.scrollTo(curTab.y, 0);
|
||
});
|
||
}
|
||
});
|
||
},
|
||
async getCategories() {
|
||
return new Promise((resolve, reject) => {
|
||
this.$api
|
||
.get('/v1/product/categories')
|
||
.then((resData) => {
|
||
resData.unshift({
|
||
icon: "",
|
||
id: -999,
|
||
name: "全部"
|
||
})
|
||
this.tabsList = resData.map((e) => {
|
||
return {
|
||
...e,
|
||
num: 1,
|
||
y: 0,
|
||
curPageLen: 0,
|
||
hasNext: true,
|
||
goods: null,
|
||
};
|
||
});
|
||
if (!!this.id) {
|
||
const index = resData.findIndex(({ id }) => id == this.id);
|
||
this.tabChange(index >= 0 ? index : 0);
|
||
}
|
||
resolve(resData);
|
||
})
|
||
.catch((err) => {
|
||
reject(err);
|
||
});
|
||
});
|
||
},
|
||
async getGoodsList({ num, size }) {
|
||
let keyword = this.tabsList[this.tabsCurrent].id;
|
||
try {
|
||
const resData = await this.$api.get('/v1/product/products', {
|
||
params: {
|
||
sort: this.filter.sort,
|
||
per_page: size,
|
||
page: num,
|
||
category: keyword == -999 ? '' : keyword,
|
||
},
|
||
});
|
||
const { data } = resData;
|
||
let curTab = this.tabsList[this.tabsCurrent];
|
||
if (num === 1) curTab.goods = [];
|
||
curTab.goods = curTab.goods.concat(data);
|
||
curTab.num = num;
|
||
curTab.curPageLen = data.length;
|
||
curTab.hasNext = this.mescroll.optUp.hasNext;
|
||
this.mescroll.endSuccess(data.length, size == data.length);
|
||
} catch (error) {
|
||
this.mescroll.endErr();
|
||
}
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
<style lang="scss" scoped>
|
||
.badge {
|
||
@apply bg-badge;
|
||
}
|
||
</style>
|