uniapp【修复】: 修复页面下拉刷新时数据重复问题

This commit is contained in:
15093570141
2024-11-11 16:50:19 +08:00
parent f850432958
commit 6113df717d
10 changed files with 925 additions and 904 deletions

View File

@@ -1,64 +1,64 @@
<template> <template>
<view :class="props.type == 'horizontal' ? 'horizontal-good-card-box' : 'vertical-good-card-box'"> <view :class="props.type == 'horizontal' ? 'horizontal-good-card-box' : 'vertical-good-card-box'">
<view class="img-box" :style="{ 'width': props.imgWidth, 'height': props.imgHeight }" @click="hanldeClickGoods"> <view class="img-box" :style="{ 'width': props.imgWidth, 'height': props.imgHeight }" @click="hanldeClickGoods">
<image class="good-img" :src="props.goodsData.image"></image> <image class="good-img" :src="props.goodsData.image"></image>
<view class="recommend" v-if="props.goodsData.isRecommend">推荐</view> <view class="recommend" v-if="props.goodsData.isRecommend">推荐</view>
<view class="hot" v-if="props.goodsData.isHot">热门</view> <view class="hot" v-if="props.goodsData.isHot">热门</view>
</view> </view>
<view class="good-msg" <view class="good-msg"
:style="{ 'width': props.type == 'horizontal' ? `calc(100% - 10px - ${props.imgWidth})` : props.imgWidth}"> :style="{ 'width': props.type == 'horizontal' ? `calc(100% - 10px - ${props.imgWidth})` : props.imgWidth}">
<view v-if="props.goodsData.name" :class="props.nameOverflow === 1 ? 'name' : 'name-two'" <view v-if="props.goodsData.name" :class="props.nameOverflow === 1 ? 'name' : 'name-two'"
@click="hanldeClickGoods"> @click="hanldeClickGoods">
{{ props.goodsData.name }} {{ props.goodsData.name }}
</view> </view>
<view v-if="props.goodsData.brief" :class="props.briefOverflow === 1 ? 'desc' : 'desc-two'" <view v-if="props.goodsData.brief" :class="props.briefOverflow === 1 ? 'desc' : 'desc-two'"
@click="hanldeClickGoods"> @click="hanldeClickGoods">
{{ props.goodsData.brief }} {{ props.goodsData.brief }}
</view> </view>
<slot name="goodTag"></slot> <slot name="goodTag"></slot>
<slot name="goodPrice"> <slot name="goodPrice">
<view class="price-msg"> <view class="price-msg">
<view class="price-box"> <view class="price-box">
<view class="price"> <view class="price">
<text class="symbol"></text> <text class="symbol"></text>
<text class="num">{{ props.goodsData.price }}</text> <text class="num">{{ props.goodsData.price }}</text>
</view> </view>
<view class="underlin-price">{{ props.goodsData.mktprice }}</view> <view class="underlin-price">{{ props.goodsData.mktprice }}</view>
</view> </view>
<view class="btn"> <view class="btn">
立即购买 立即购买
</view> </view>
</view> </view>
</slot> </slot>
</view> </view>
</view> </view>
<slot name="other"></slot> <slot name="other"></slot>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
type : 'vertical' | 'horizontal', type ?: 'vertical' | 'horizontal',
imgWidth : string, imgWidth ?: string,
imgHeight : string, imgHeight ?: string,
nameOverflow : number, nameOverflow ?: number,
briefOverflow : number, briefOverflow ?: number,
goodsData : any, goodsData ?: any,
}>(), { }>(), {
type: 'horizontal', // vertical 垂直 horizontal 水平 type: 'horizontal', // vertical 垂直 horizontal 水平
imgWidth: '190rpx', imgWidth: '190rpx',
imgHeight: '190rpx', imgHeight: '190rpx',
nameOverflow: 1, nameOverflow: 1,
briefOverflow: 1, briefOverflow: 1,
goodsData: {}, goodsData: {},
}); });
const emit = defineEmits(['hanldeClickGoods']); const emit = defineEmits(['hanldeClickGoods']);
const hanldeClickGoods = () => { const hanldeClickGoods = () => {
emit('hanldeClickGoods', props.goodsData) emit('hanldeClickGoods', props.goodsData)
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import './coreshop-goods-card.scss'; @import './coreshop-goods-card.scss';
</style> </style>

View File

@@ -1,39 +1,39 @@
<template> <template>
<view class="more-box" @click="hanldeClickViewMore"> <view class="more-box" @click="hanldeClickViewMore">
<text class="more-text" :style="{ 'color': props.color }">{{ props.title }}</text> <text class="more-text" :style="{ 'color': props.color }">{{ props.title }}</text>
<view class="more-icon"> <view class="more-icon">
<uv-icon name="arrow-right" :color="props.color" :size="15"></uv-icon> <uv-icon name="arrow-right" :color="props.color" :size="15"></uv-icon>
</view> </view>
</view> </view>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
title : string, title ?: string,
color : string, color ?: string,
}>(), { }>(), {
title: '查看更多', title: '查看更多',
color: '#6E737D' color: '#6E737D'
}); });
const emit = defineEmits(['hanldeClickViewMore']); const emit = defineEmits(['hanldeClickViewMore']);
const hanldeClickViewMore = () => { const hanldeClickViewMore = () => {
emit('hanldeClickViewMore'); emit('hanldeClickViewMore');
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.more-box { .more-box {
display: flex; display: flex;
align-items: center; align-items: center;
.more-text { .more-text {
font-size: 24rpx; font-size: 24rpx;
} }
.more-icon { .more-icon {
width: 30rpx; width: 30rpx;
height: 30rpx; height: 30rpx;
margin-top: 2rpx; margin-top: 2rpx;
} }
} }
</style> </style>

View File

@@ -3,3 +3,6 @@ export const onHomePageShow = "onHomePageShow";
/** 监听分类onHide需要的常量字段 */ /** 监听分类onHide需要的常量字段 */
export const onClassifyPageHide = "onClassifyPageHide"; export const onClassifyPageHide = "onClassifyPageHide";
/** 监听上拉刷新onPullDownRefresh要的常量字段 */
export const onClassifyPagePullDownRefresh = "onClassifyPagePullDownRefresh";

View File

@@ -240,6 +240,7 @@
onPullDownRefresh(async () => { onPullDownRefresh(async () => {
state.page = 1; state.page = 1;
state.totalPages = 1; state.totalPages = 1;
state.goodsList = [[], []];
await handleuQueryProduct(queryParams); await handleuQueryProduct(queryParams);
uni.stopPullDownRefresh(); uni.stopPullDownRefresh();
}); });

View File

@@ -1,410 +1,416 @@
<template> <template>
<view class="layout-classify" :style="{ height: `${props.height}px` }"> <view class="layout-classify" :style="{ height: `${props.height}px` }">
<!-- 头部大分类 --> <!-- 头部大分类 -->
<view class="big-classify"> <view class="big-classify">
<view class="scroll-view-box"> <view class="scroll-view-box">
<scroll-view class="scroll-view" enable-flex :scroll-x="true" :scroll-left="state.topScrollLeft" <scroll-view class="scroll-view" enable-flex :scroll-x="true" :scroll-left="state.topScrollLeft"
:scroll-with-animation="true"> :scroll-with-animation="true">
<view :class="['item', { 'on': state.topTabId === item.id }]" <view :class="['item', { 'on': state.topTabId === item.id }]"
v-for="item, index in state.classifyData" :key="index" @click="hanldeChangeTopTab(item, index)"> v-for="item, index in state.classifyData" :key="index" @click="hanldeChangeTopTab(item, index)">
<view class="img-box"> <view class="img-box">
<image class="img" :src="item.imageUrl"></image> <image class="img" :src="item.imageUrl"></image>
</view> </view>
<view> <view>
<text class="tit">{{ item.name }}</text> <text class="tit">{{ item.name }}</text>
</view> </view>
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
<view class="all-big-classify" @click="hanldeShowBigClassifyPop"> <view class="all-big-classify" @click="hanldeShowBigClassifyPop">
<text class="tit">全部</text> <text class="tit">全部</text>
<image class="img" :src="handleStaticResources('/static/images/icon/all-drop-down.png')"></image> <image class="img" :src="handleStaticResources('/static/images/icon/all-drop-down.png')"></image>
</view> </view>
</view> </view>
<view class="classify-box" :style="{ height: `${props.height - state.bigClassifyH}px` }"> <view class="classify-box" :style="{ height: `${props.height - state.bigClassifyH}px` }">
<view class="classify-left"> <view class="classify-left">
<scroll-view class="scroll-view" enable-flex :scroll-y="true"> <scroll-view class="scroll-view" enable-flex :scroll-y="true">
<view :class="['item', { 'on': state.leftTabId === item.id }]" <view :class="['item', { 'on': state.leftTabId === item.id }]"
v-for="item, index in state.leftTabList" :key="index" @click="hanldeChangeLeftTab(item)"> v-for="item, index in state.leftTabList" :key="index" @click="hanldeChangeLeftTab(item)">
{{ item.name }} {{ item.name }}
</view> </view>
<view class="no-more"></view> <view class="no-more"></view>
</scroll-view> </scroll-view>
</view> </view>
<view class="classify-right"> <view class="classify-right">
<view class="right-tab-box"> <view class="right-tab-box">
<view> <view>
<coreshop-tabs :list="state.rightTabList" <coreshop-tabs :list="state.rightTabList"
@hanldeClickTab="hanldeChangeRightTab"></coreshop-tabs> @hanldeClickTab="hanldeChangeRightTab"></coreshop-tabs>
</view> </view>
</view> </view>
<scroll-view class="scroll-view" enable-flex <scroll-view class="scroll-view" enable-flex
:style="{ 'height': `${props.height - state.bigClassifyH - state.rightTabH}px` }" :scroll-y="true" :style="{ 'height': `${props.height - state.bigClassifyH - state.rightTabH}px` }" :scroll-y="true"
@scrolltolower="handleScrolltolower"> @scrolltolower="handleScrolltolower">
<view class="advert-box radius-15"> <view class="advert-box radius-15">
<coreshop-advert :code="advertPosition.goodsClassifyBanner"></coreshop-advert> <coreshop-advert :code="advertPosition.goodsClassifyBanner"></coreshop-advert>
</view> </view>
<view class="data-box" v-if="state.goodsList.length > 0"> <view class="data-box" v-if="state.goodsList.length > 0">
<view class="item-box" v-for="item in state.goodsList" :key="item.id"> <view class="item-box" v-for="item in state.goodsList" :key="item.id">
<coreshop-goods-card imgWidth="150rpx" imgHeight="150rpx" <coreshop-goods-card imgWidth="150rpx" imgHeight="150rpx"
:goodsData="hanldeCombinationGoodsData(item)" @hanldeClickGoods="hanldeClickGoods"> :goodsData="hanldeCombinationGoodsData(item)" @hanldeClickGoods="hanldeClickGoods">
<template #goodPrice> <template #goodPrice>
<view class="price-msg"> <view class="price-msg">
<view class="price-box"> <view class="price-box">
<view class="price"> <view class="price">
<text class="symbol"></text> <text class="symbol"></text>
<text class="num">{{ item.price }}</text> <text class="num">{{ item.price }}</text>
</view> </view>
<view class="underlin-price">{{ item.mktprice }}</view> <view class="underlin-price">{{ item.mktprice }}</view>
</view> </view>
<view class="btn" @click="handleSelectSku(item.id)"> <view class="btn" @click="handleSelectSku(item.id)">
<image class="img" :src="handleStaticResources('/static/images/cart.png')"> <image class="img" :src="handleStaticResources('/static/images/cart.png')">
</image> </image>
</view> </view>
</view> </view>
</template> </template>
</coreshop-goods-card> </coreshop-goods-card>
</view> </view>
<view class="no-more"> <view class="no-more">
<uv-divider :dashed="true" <uv-divider :dashed="true"
:text="state.totalPages > state.page ? '下滑加载更多' : '没有更多了'"></uv-divider> :text="state.totalPages > state.page ? '下滑加载更多' : '没有更多了'"></uv-divider>
</view> </view>
</view> </view>
<view v-else> <view v-else>
<coreshop-empty></coreshop-empty> <coreshop-empty></coreshop-empty>
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
</view> </view>
<!-- 购物车盒子 --> <!-- 购物车盒子 -->
<view class="shopping-box"> <view class="shopping-box">
<view class="shopping-Bag"> <view class="shopping-Bag">
<view class="bag-box"> <view class="bag-box">
<image class="img" :src="handleStaticResources('/static/images/cart-bag.png')"></image> <image class="img" :src="handleStaticResources('/static/images/cart-bag.png')"></image>
</view> </view>
<view class="price-box"> <view class="price-box">
<text class="num">购物车数量:{{ state.cartCount }}</text> <text class="num">购物车数量:{{ state.cartCount }}</text>
<text class="price">{{ state.cartMoney }}</text> <text class="price">{{ state.cartMoney }}</text>
</view> </view>
</view> </view>
<view class="btn-buy" @click="handleGoPay"> <view class="btn-buy" @click="handleGoPay">
去结算 去结算
</view> </view>
</view> </view>
<!-- 商品sku弹框 --> <!-- 商品sku弹框 -->
<GoodsDetailSkuPopup :showSku="state.showSku" :goodsDetailData="state.goodsDetailData" <GoodsDetailSkuPopup :showSku="state.showSku" :goodsDetailData="state.goodsDetailData"
:safeAreaInsetBottom="false" :buyNowNowloading="buyNowLoading" :addCartloading="addCartLoading" :safeAreaInsetBottom="false" :buyNowNowloading="buyNowLoading" :addCartloading="addCartLoading"
@handleChangePopup="handleChangePopup" @handleAddCart="handleAddCart" @handleBuyNow="handleBuyNow"> @handleChangePopup="handleChangePopup" @handleAddCart="handleAddCart" @handleBuyNow="handleBuyNow">
</GoodsDetailSkuPopup> </GoodsDetailSkuPopup>
<!-- 头部大分类的弹框 --> <!-- 头部大分类的弹框 -->
<uv-popup ref="bigClassifyPop" mode="top" :safeAreaInsetBottom="false"> <uv-popup ref="bigClassifyPop" mode="top" :safeAreaInsetBottom="false">
<view class="big-classify-pop" :style="{ 'padding-top': `${props.statusBarHeight}px` }"> <view class="big-classify-pop" :style="{ 'padding-top': `${props.statusBarHeight}px` }">
<view class="title">全部分类</view> <view class="title">全部分类</view>
<view class="item-box"> <view class="item-box">
<view :class="['item', { 'on': state.topTabId === item.id }]" <view :class="['item', { 'on': state.topTabId === item.id }]"
v-for="item, index in state.classifyData" :key="index" @click="hanldeChangeTopTab(item, index)"> v-for="item, index in state.classifyData" :key="index" @click="hanldeChangeTopTab(item, index)">
<view class="img-box"> <view class="img-box">
<image class="img" :src="item.imageUrl"></image> <image class="img" :src="item.imageUrl"></image>
</view> </view>
<view> <view>
<text class="tit">{{ item.name }}</text> <text class="tit">{{ item.name }}</text>
</view> </view>
</view> </view>
</view> </view>
<view class="put-away" @click="hanlderHidebigClassifyPop">点击收起<uv-icon name="arrow-up" size="15px" <view class="put-away" @click="hanlderHidebigClassifyPop">点击收起<uv-icon name="arrow-up" size="15px"
color="6E737D"></uv-icon></view> color="6E737D"></uv-icon></view>
</view> </view>
</uv-popup> </uv-popup>
</view> </view>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, watch, ref, onMounted, getCurrentInstance, nextTick } from 'vue'; import { reactive, watch, ref, onMounted, getCurrentInstance, nextTick } from 'vue';
import { advertPosition, UserToken, onClassifyPageHide } from '@/core/consts'; import { advertPosition, UserToken, onClassifyPageHide, onClassifyPagePullDownRefresh } from '@/core/consts';
import { useLoginStore } from '@/core/store'; import { useLoginStore } from '@/core/store';
import { queryGoodsPageList, queryCartNumAndMoney, queryGoodsDetailByToken, queryGoodsDetail, queryAddCart } from '@/core/api'; import { queryGoodsPageList, queryCartNumAndMoney, queryGoodsDetailByToken, queryGoodsDetail, queryAddCart } from '@/core/api';
import type { CategoriesType, Response, GoodsListType, GoodsType } from '@/core/models'; import type { CategoriesType, Response, GoodsListType, GoodsType } from '@/core/models';
import { getDomInfo, handleStaticResources, handleRouteNavigateTo, handleShowToast, handleRouteSwitchTab } from '@/core/utils'; import { getDomInfo, handleStaticResources, handleRouteNavigateTo, handleShowToast, handleRouteSwitchTab } from '@/core/utils';
import { AddCartEnum, PaymentTypeEnum, RouteSwitchTabEnum } from '@/core/enum'; import { AddCartEnum, PaymentTypeEnum, RouteSwitchTabEnum } from '@/core/enum';
import GoodsDetailSkuPopup from '@/pages/components/goods-detail/components/goods-detail-sku/goods-detail-sku.vue'; import GoodsDetailSkuPopup from '@/pages/components/goods-detail/components/goods-detail-sku/goods-detail-sku.vue';
import { useLoadingFn } from '@/core/hooks'; import { useLoadingFn } from '@/core/hooks';
const instance = getCurrentInstance(); const instance = getCurrentInstance();
/** 登录store */ /** 登录store */
const _useLoginStore = useLoginStore(); const _useLoginStore = useLoginStore();
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
data : Array<CategoriesType>, data : Array<CategoriesType>,
height : number, height : number,
statusBarHeight : number, statusBarHeight : number,
}>(), { }>(), {
data: () => [], data: () => [],
height: 0, height: 0,
statusBarHeight: 0, statusBarHeight: 0,
}); });
const bigClassifyPop = ref(); const bigClassifyPop = ref();
const state = reactive<{ const state = reactive<{
classifyData : Array<CategoriesType>; classifyData : Array<CategoriesType>;
topTabId : number; topTabId : number;
topScrollLeft : number; topScrollLeft : number;
leftTabId : number; leftTabId : number;
leftTabList : Array<CategoriesType>; leftTabList : Array<CategoriesType>;
rightTabList : Array<CategoriesType>; rightTabList : Array<CategoriesType>;
catId : number; catId : number;
goodsList : Array<GoodsType>; goodsList : Array<GoodsType>;
page : number; page : number;
totalPages : number; totalPages : number;
bigClassifyH : number; // 大分类盒子的高度 bigClassifyH : number; // 大分类盒子的高度
rightTabH : number; // 右侧tab盒子的高度 rightTabH : number; // 右侧tab盒子的高度
cartCount : number; cartCount : number;
cartMoney : number, cartMoney : number,
showSku : boolean; showSku : boolean;
goodsDetailData : any; goodsDetailData : any;
}>({ }>({
classifyData: [], classifyData: [],
topTabId: 0, topTabId: 0,
topScrollLeft: 0, topScrollLeft: 0,
leftTabId: 0, leftTabId: 0,
leftTabList: [], leftTabList: [],
rightTabList: [], rightTabList: [],
catId: 0, catId: 0,
goodsList: [], goodsList: [],
page: 1, page: 1,
totalPages: 0, totalPages: 0,
bigClassifyH: 0, bigClassifyH: 0,
rightTabH: 0, rightTabH: 0,
cartCount: 0, cartCount: 0,
cartMoney: 0, cartMoney: 0,
showSku: false, showSku: false,
goodsDetailData: {}, goodsDetailData: {},
}); });
const buyNowLoading = ref(false); const buyNowLoading = ref(false);
const addCartLoading = ref(false); const addCartLoading = ref(false);
const handleBuyNow = useLoadingFn(onBuyNow, buyNowLoading); const handleBuyNow = useLoadingFn(onBuyNow, buyNowLoading);
const handleAddCart = useLoadingFn(onAddCart, addCartLoading) const handleAddCart = useLoadingFn(onAddCart, addCartLoading)
watch(() => props.data, (newVal : Array<CategoriesType>) => { watch(() => props.data, (newVal : Array<CategoriesType>) => {
if (newVal) { if (newVal) {
state.classifyData = newVal.map((item : CategoriesType) => { state.classifyData = newVal.map((item : CategoriesType) => {
item.child.forEach((cell : CategoriesType) => { item.child.forEach((cell : CategoriesType) => {
cell.child.unshift({ cell.child.unshift({
name: "全部", name: "全部",
id: cell.id, id: cell.id,
}) })
}) })
return item; return item;
}); });
state.topTabId = state.classifyData[0]?.id; state.topTabId = state.classifyData[0]?.id;
state.leftTabId = state.classifyData[0]?.child[0]?.id; state.leftTabId = state.classifyData[0]?.child[0]?.id;
state.leftTabList = state.classifyData[0]?.child; state.leftTabList = state.classifyData[0]?.child;
state.rightTabList = state.classifyData[0]?.child[0]?.child; state.rightTabList = state.classifyData[0]?.child[0]?.child;
state.catId = state.classifyData[0].child[0]?.id; state.catId = state.classifyData[0]?.child[0]?.id;
getGoodsPageList(); getGoodsPageList();
} }
}) })
onMounted(() => { onMounted(() => {
if (uni.getStorageSync(UserToken)) { if (uni.getStorageSync(UserToken)) {
getCartNumAndMoney(); getCartNumAndMoney();
} }
uni.$on(onClassifyPageHide, () => { uni.$on(onClassifyPagePullDownRefresh, () => {
state.showSku = false; state.page = 1;
}) state.totalPages = 1;
state.goodsList = [];
})
nextTick(async () => { uni.$on(onClassifyPageHide, () => {
state.bigClassifyH = ((await getDomInfo('.big-classify', instance.proxy)) as { height : number }).height; state.showSku = false;
setTimeout(async () => { })
state.rightTabH = ((await getDomInfo('.right-tab-box', instance.proxy)) as { height : number }).height;
}, 100)
})
})
// 获取商品列表数据 nextTick(async () => {
const getGoodsPageList = async () => { state.bigClassifyH = ((await getDomInfo('.big-classify', instance.proxy)) as { height : number }).height;
setTimeout(async () => {
state.rightTabH = ((await getDomInfo('.right-tab-box', instance.proxy)) as { height : number }).height;
}, 100)
})
})
const goodsPageList : Response<GoodsListType> = await queryGoodsPageList({ // 获取商品列表数据
page: state.page, const getGoodsPageList = async () => {
limit: 10, if (!state.catId) { return; }
where: `{"catId":${state.catId}}` const goodsPageList : Response<GoodsListType> = await queryGoodsPageList({
}); page: state.page,
if (goodsPageList.status) { limit: 10,
state.totalPages = goodsPageList.data?.totalPages; where: `{"catId":${state.catId}}`
state.goodsList = state.goodsList.concat(goodsPageList.data?.list); });
} if (goodsPageList.status) {
} state.totalPages = goodsPageList.data?.totalPages;
state.goodsList = state.goodsList.concat(goodsPageList.data?.list);
}
}
/** 获取购物车数量和价格 */ /** 获取购物车数量和价格 */
const getCartNumAndMoney = async () => { const getCartNumAndMoney = async () => {
const cartNumAndMoney : Response<{ count : number, money : number }> = await queryCartNumAndMoney(); const cartNumAndMoney : Response<{ count : number, money : number }> = await queryCartNumAndMoney();
state.cartCount = cartNumAndMoney?.data?.count || 0; state.cartCount = cartNumAndMoney?.data?.count || 0;
state.cartMoney = cartNumAndMoney?.data?.money || 0; state.cartMoney = cartNumAndMoney?.data?.money || 0;
} }
/** 选择sku */ /** 选择sku */
const handleSelectSku = (id : number) => { const handleSelectSku = (id : number) => {
_useLoginStore.checkLogin(async () => { _useLoginStore.checkLogin(async () => {
let goodsDetail : any = null; let goodsDetail : any = null;
if (uni.getStorageSync(UserToken)) { if (uni.getStorageSync(UserToken)) {
goodsDetail = await queryGoodsDetailByToken({ goodsDetail = await queryGoodsDetailByToken({
id: id, id: id,
data: true, data: true,
}) })
} else { } else {
goodsDetail = await queryGoodsDetail({ goodsDetail = await queryGoodsDetail({
id: id, id: id,
data: true, data: true,
}) })
} }
state.goodsDetailData = goodsDetail.data; state.goodsDetailData = goodsDetail.data;
state.showSku = true; state.showSku = true;
}); });
} }
/** 底部按钮去结算 */ /** 底部按钮去结算 */
const handleGoPay = () => { const handleGoPay = () => {
_useLoginStore.checkLogin(() => { _useLoginStore.checkLogin(() => {
handleRouteSwitchTab(RouteSwitchTabEnum.cart); handleRouteSwitchTab(RouteSwitchTabEnum.cart);
}); });
} }
/** 添加购物车 */ /** 添加购物车 */
async function onAddCart({ productId, nums } : any) { async function onAddCart({ productId, nums } : any) {
const addCart : Response<number> = await queryAddCart({ const addCart : Response<number> = await queryAddCart({
productId, productId,
nums, nums,
type: AddCartEnum.add, type: AddCartEnum.add,
}); });
if (addCart.status) { if (addCart.status) {
handleShowToast(addCart.msg, "success"); handleShowToast(addCart.msg, "success");
/** 添加成功后,重新获取购物车数量和价格 */ /** 添加成功后,重新获取购物车数量和价格 */
getCartNumAndMoney(); getCartNumAndMoney();
/** 关闭sku弹框 */ /** 关闭sku弹框 */
handleChangePopup(false); handleChangePopup(false);
} else { } else {
handleShowToast(addCart.msg); handleShowToast(addCart.msg);
} }
} }
/** 立即购买 */ /** 立即购买 */
async function onBuyNow({ productId, nums } : any) { async function onBuyNow({ productId, nums } : any) {
const addCart : Response<number> = await queryAddCart({ const addCart : Response<number> = await queryAddCart({
productId, productId,
nums, nums,
type: AddCartEnum.buy, type: AddCartEnum.buy,
cartType: PaymentTypeEnum.common, cartType: PaymentTypeEnum.common,
}); });
if (addCart.status) { if (addCart.status) {
handleRouteNavigateTo(`/pages/order/submit/submit?cartIds=${addCart.data}`) handleRouteNavigateTo(`/pages/order/submit/submit?cartIds=${addCart.data}`)
/** 关闭sku弹框 */ /** 关闭sku弹框 */
handleChangePopup(false); handleChangePopup(false);
} else { } else {
handleShowToast(addCart.msg); handleShowToast(addCart.msg);
} }
} }
/** sku弹框显示隐藏 */ /** sku弹框显示隐藏 */
const handleChangePopup = (show : boolean) => { const handleChangePopup = (show : boolean) => {
state.showSku = show; state.showSku = show;
} }
/** 切换顶部tab */ /** 切换顶部tab */
const hanldeChangeTopTab = (item : CategoriesType, index : number) => { const hanldeChangeTopTab = (item : CategoriesType, index : number) => {
if (state.leftTabId != item.id) { if (state.leftTabId != item.id) {
state.topTabId = item.id; state.topTabId = item.id;
state.catId = item.id; state.catId = item.id;
state.leftTabId = item?.child[0].id; state.leftTabId = item?.child[0].id;
state.leftTabList = item?.child; state.leftTabList = item?.child;
state.rightTabList = item?.child[0]?.child; state.rightTabList = item?.child[0]?.child;
calculationTopMovingDistance(index); calculationTopMovingDistance(index);
handleResetGoodsList(); handleResetGoodsList();
hanlderHidebigClassifyPop(); hanlderHidebigClassifyPop();
} }
} }
/** 显示顶部大分类弹框 */ /** 显示顶部大分类弹框 */
const hanldeShowBigClassifyPop = () => { const hanldeShowBigClassifyPop = () => {
bigClassifyPop.value.open(); bigClassifyPop.value.open();
} }
/** 隐藏顶部大分类弹框 */ /** 隐藏顶部大分类弹框 */
const hanlderHidebigClassifyPop = () => { const hanlderHidebigClassifyPop = () => {
bigClassifyPop.value.close(); bigClassifyPop.value.close();
} }
/** 计算顶部tab移动的距离 */ /** 计算顶部tab移动的距离 */
const calculationTopMovingDistance = (index : number) => { const calculationTopMovingDistance = (index : number) => {
let topScrollLeft = 0; let topScrollLeft = 0;
for (let i = 0; i < index - 1; i++) { for (let i = 0; i < index - 1; i++) {
topScrollLeft += 60 topScrollLeft += 60
}; };
state.topScrollLeft = topScrollLeft state.topScrollLeft = topScrollLeft
} }
/** 切换左侧tab */ /** 切换左侧tab */
const hanldeChangeLeftTab = (item : CategoriesType) => { const hanldeChangeLeftTab = (item : CategoriesType) => {
if (state.leftTabId != item.id) { if (state.leftTabId != item.id) {
state.leftTabId = item.id; state.leftTabId = item.id;
state.catId = item.id; state.catId = item.id;
state.rightTabList = item?.child; state.rightTabList = item?.child;
handleResetGoodsList(); handleResetGoodsList();
} }
} }
/** 切换右侧tab */ /** 切换右侧tab */
const hanldeChangeRightTab = (item : CategoriesType) => { const hanldeChangeRightTab = (item : CategoriesType) => {
state.catId = item.id; state.catId = item.id;
handleResetGoodsList(); handleResetGoodsList();
} }
/** 组合商品数据传入组件 */ /** 组合商品数据传入组件 */
const hanldeCombinationGoodsData = (item : GoodsType) => { const hanldeCombinationGoodsData = (item : GoodsType) => {
return { return {
id: item.id, id: item.id,
image: item.image, image: item.image,
name: item.name, name: item.name,
brief: item.brief, brief: item.brief,
price: item.price, price: item.price,
mktprice: item.mktprice, mktprice: item.mktprice,
isRecommend: item.isRecommend, isRecommend: item.isRecommend,
isHot: item.isHot, isHot: item.isHot,
} }
} }
const hanldeClickGoods = (item : GoodsType) => { const hanldeClickGoods = (item : GoodsType) => {
uni.navigateTo({ uni.navigateTo({
url: `/pages/goods/detail?id=${item.id}` url: `/pages/goods/detail?id=${item.id}`
}) })
} }
/** 加载下一页数据 */ /** 加载下一页数据 */
const handleScrolltolower = () => { const handleScrolltolower = () => {
if (state.totalPages > state.page) { if (state.totalPages > state.page) {
state.page++; state.page++;
getGoodsPageList(); getGoodsPageList();
} }
} }
/** 重置商品列表数据 */ /** 重置商品列表数据 */
const handleResetGoodsList = () => { const handleResetGoodsList = () => {
state.page = 1; state.page = 1;
state.goodsList = []; state.goodsList = [];
getGoodsPageList(); getGoodsPageList();
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import './classify-five.scss'; @import './classify-five.scss';
</style> </style>

View File

@@ -1,301 +1,307 @@
<template> <template>
<view class="classify-box" :style="{ height: `${props.height}px` }"> <view class="classify-box" :style="{ height: `${props.height}px` }">
<view class="classify-left"> <view class="classify-left">
<scroll-view class="scroll-view" :scroll-y="true"> <scroll-view class="scroll-view" :scroll-y="true">
<view :class="['item', { 'on': state.leftTabId === item.id }]" v-for="item, index in state.classifyData" <view :class="['item', { 'on': state.leftTabId === item.id }]" v-for="item, index in state.classifyData"
:key="index" @click="hanldeChangeLeftTab(item)"> :key="index" @click="hanldeChangeLeftTab(item)">
{{ item.name }} {{ item.name }}
</view> </view>
<view class="no-more"></view> <view class="no-more"></view>
</scroll-view> </scroll-view>
</view> </view>
<view class="classify-right"> <view class="classify-right">
<view class="right-tab-box"> <view class="right-tab-box">
<coreshop-tabs :list="state.rightTabList" @hanldeClickTab="hanldeChangeRightTab"></coreshop-tabs> <coreshop-tabs :list="state.rightTabList" @hanldeClickTab="hanldeChangeRightTab"></coreshop-tabs>
</view> </view>
<view class="right-data-list"> <view class="right-data-list">
<scroll-view class="scroll-view" :scroll-y="true" @scrolltolower="handleScrolltolower"> <scroll-view class="scroll-view" :scroll-y="true" @scrolltolower="handleScrolltolower">
<view class="advert-box radius-15"> <view class="advert-box radius-15">
<coreshop-advert :code="advertPosition.goodsClassifyBanner"></coreshop-advert> <coreshop-advert :code="advertPosition.goodsClassifyBanner"></coreshop-advert>
</view> </view>
<view class="data-box" v-if="state.goodsList.length > 0"> <view class="data-box" v-if="state.goodsList.length > 0">
<view class="item-box" v-for="item in state.goodsList" :key="item.id"> <view class="item-box" v-for="item in state.goodsList" :key="item.id">
<coreshop-goods-card imgWidth="150rpx" imgHeight="150rpx" <coreshop-goods-card imgWidth="150rpx" imgHeight="150rpx"
:goodsData="hanldeCombinationGoodsData(item)" @hanldeClickGoods="hanldeClickGoods"> :goodsData="hanldeCombinationGoodsData(item)" @hanldeClickGoods="hanldeClickGoods">
<template #goodPrice> <template #goodPrice>
<view class="price-msg"> <view class="price-msg">
<view class="price-box"> <view class="price-box">
<view class="price"> <view class="price">
<text class="symbol"></text> <text class="symbol"></text>
<text class="num">{{ item.price }}</text> <text class="num">{{ item.price }}</text>
</view> </view>
<view class="underlin-price">{{ item.mktprice }}</view> <view class="underlin-price">{{ item.mktprice }}</view>
</view> </view>
<view class="btn" @click="handleSelectSku(item.id)"> <view class="btn" @click="handleSelectSku(item.id)">
<image class="img" :src="handleStaticResources('/static/images/cart.png')"> <image class="img" :src="handleStaticResources('/static/images/cart.png')">
</image> </image>
</view> </view>
</view> </view>
</template> </template>
</coreshop-goods-card> </coreshop-goods-card>
</view> </view>
<view class="no-more"> <view class="no-more">
<uv-divider :dashed="true" <uv-divider :dashed="true"
:text="state.totalPages > state.page ? '下滑加载更多' : '没有更多了'"></uv-divider> :text="state.totalPages > state.page ? '下滑加载更多' : '没有更多了'"></uv-divider>
</view> </view>
</view> </view>
<view v-else> <view v-else>
<coreshop-empty></coreshop-empty> <coreshop-empty></coreshop-empty>
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
</view> </view>
<view class="shopping-box"> <view class="shopping-box">
<view class="shopping-Bag"> <view class="shopping-Bag">
<view class="bag-box"> <view class="bag-box">
<image class="img" :src="handleStaticResources('/static/images/cart-bag.png')"></image> <image class="img" :src="handleStaticResources('/static/images/cart-bag.png')"></image>
</view> </view>
<view class="price-box"> <view class="price-box">
<text class="num">购物车数量:{{ state.cartCount }}</text> <text class="num">购物车数量:{{ state.cartCount }}</text>
<text class="price">{{ state.cartMoney }}</text> <text class="price">{{ state.cartMoney }}</text>
</view> </view>
</view> </view>
<view class="btn-buy" @click="handleGoPay"> <view class="btn-buy" @click="handleGoPay">
去结算 去结算
</view> </view>
</view> </view>
<!-- 商品sku弹框 --> <!-- 商品sku弹框 -->
<GoodsDetailSkuPopup :showSku="state.showSku" :goodsDetailData="state.goodsDetailData" <GoodsDetailSkuPopup :showSku="state.showSku" :goodsDetailData="state.goodsDetailData"
:safeAreaInsetBottom="false" :buyNowNowloading="buyNowLoading" :addCartloading="addCartLoading" :safeAreaInsetBottom="false" :buyNowNowloading="buyNowLoading" :addCartloading="addCartLoading"
@handleChangePopup="handleChangePopup" @handleAddCart="handleAddCart" @handleBuyNow="handleBuyNow"> @handleChangePopup="handleChangePopup" @handleAddCart="handleAddCart" @handleBuyNow="handleBuyNow">
</GoodsDetailSkuPopup> </GoodsDetailSkuPopup>
</view> </view>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, reactive, ref, watch, nextTick } from 'vue'; import { onMounted, reactive, ref, watch } from 'vue';
import { UserToken, advertPosition, onClassifyPageHide } from '@/core/consts'; import { UserToken, advertPosition, onClassifyPageHide, onClassifyPagePullDownRefresh } from '@/core/consts';
import { queryGoodsPageList, queryCartNumAndMoney, queryGoodsDetailByToken, queryGoodsDetail, queryAddCart } from '@/core/api'; import { queryGoodsPageList, queryCartNumAndMoney, queryGoodsDetailByToken, queryGoodsDetail, queryAddCart } from '@/core/api';
import type { CategoriesType, Response, GoodsListType, GoodsType } from '@/core/models'; import type { CategoriesType, Response, GoodsListType, GoodsType } from '@/core/models';
import { handleStaticResources, handleRouteNavigateTo, handleShowToast, handleRouteSwitchTab } from '@/core/utils'; import { handleStaticResources, handleRouteNavigateTo, handleShowToast, handleRouteSwitchTab } from '@/core/utils';
import { useLoginStore } from '@/core/store' import { useLoginStore } from '@/core/store'
import { AddCartEnum, PaymentTypeEnum, RouteSwitchTabEnum } from '@/core/enum'; import { AddCartEnum, PaymentTypeEnum, RouteSwitchTabEnum } from '@/core/enum';
import GoodsDetailSkuPopup from '@/pages/components/goods-detail/components/goods-detail-sku/goods-detail-sku.vue'; import GoodsDetailSkuPopup from '@/pages/components/goods-detail/components/goods-detail-sku/goods-detail-sku.vue';
import { useLoadingFn } from '@/core/hooks'; import { useLoadingFn } from '@/core/hooks';
/** 登录store */ /** 登录store */
const _useLoginStore = useLoginStore(); const _useLoginStore = useLoginStore();
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
data : Array<CategoriesType>, data : Array<CategoriesType>,
height : number, height : number,
}>(), { }>(), {
data: () => [], data: () => [],
height: 0, height: 0,
}); });
const state = reactive<{ const state = reactive<{
classifyData : Array<CategoriesType>; classifyData : Array<CategoriesType>;
leftTabId : number; leftTabId : number;
rightTabList : Array<CategoriesType>; rightTabList : Array<CategoriesType>;
catId : number; catId : number;
goodsList : Array<GoodsType>; goodsList : Array<GoodsType>;
page : number; page : number;
totalPages : number; totalPages : number;
cartCount : number; cartCount : number;
cartMoney : number, cartMoney : number,
showSku : boolean; showSku : boolean;
goodsDetailData : any; goodsDetailData : any;
}>({ }>({
classifyData: [], classifyData: [],
leftTabId: 0, leftTabId: 0,
rightTabList: [], rightTabList: [],
catId: 0, catId: 0,
goodsList: [], goodsList: [],
page: 1, page: 1,
totalPages: 0, totalPages: 0,
cartCount: 0, cartCount: 0,
cartMoney: 0, cartMoney: 0,
showSku: false, showSku: false,
goodsDetailData: {}, goodsDetailData: {},
}); });
const buyNowLoading = ref(false); const buyNowLoading = ref(false);
const addCartLoading = ref(false); const addCartLoading = ref(false);
const handleBuyNow = useLoadingFn(onBuyNow, buyNowLoading); const handleBuyNow = useLoadingFn(onBuyNow, buyNowLoading);
const handleAddCart = useLoadingFn(onAddCart, addCartLoading) const handleAddCart = useLoadingFn(onAddCart, addCartLoading)
watch(() => props.data, (newVal : Array<CategoriesType>) => { watch(() => props.data, (newVal : Array<CategoriesType>) => {
if (newVal) { if (newVal) {
state.classifyData = newVal.map((item : CategoriesType) => { state.classifyData = newVal.map((item : CategoriesType) => {
item.child.unshift({ item.child.unshift({
name: "全部", name: "全部",
id: item.id, id: item.id,
}) })
return item; return item;
}); });
state.leftTabId = state.classifyData[0]?.id; state.leftTabId = state.classifyData[0]?.id;
state.catId = state.classifyData[0]?.id; state.catId = state.classifyData[0]?.id;
state.rightTabList = state.classifyData[0]?.child; state.rightTabList = state.classifyData[0]?.child;
getGoodsPageList(); getGoodsPageList();
} }
}) })
onMounted(() => { onMounted(() => {
if (uni.getStorageSync(UserToken)) { if (uni.getStorageSync(UserToken)) {
getCartNumAndMoney(); getCartNumAndMoney();
} }
uni.$on(onClassifyPageHide, () => { uni.$on(onClassifyPagePullDownRefresh, () => {
state.showSku = false; state.page = 1;
}) state.totalPages = 1;
}); state.goodsList = [];
})
/** 获取商品列表数据 */ uni.$on(onClassifyPageHide, () => {
const getGoodsPageList = async () => { state.showSku = false;
})
});
const goodsPageList : Response<GoodsListType> = await queryGoodsPageList({ /** 获取商品列表数据 */
page: state.page, const getGoodsPageList = async () => {
limit: 10, if (!state.catId) { return; }
where: `{"catId":${state.catId}}` const goodsPageList : Response<GoodsListType> = await queryGoodsPageList({
}); page: state.page,
if (goodsPageList.status) { limit: 10,
state.totalPages = goodsPageList.data?.totalPages; where: `{"catId":${state.catId}}`
state.goodsList = state.goodsList.concat(goodsPageList.data?.list); });
} if (goodsPageList.status) {
} state.totalPages = goodsPageList.data?.totalPages;
state.goodsList = state.goodsList.concat(goodsPageList.data?.list);
}
}
/** 获取购物车数量和价格 */ /** 获取购物车数量和价格 */
const getCartNumAndMoney = async () => { const getCartNumAndMoney = async () => {
const cartNumAndMoney : Response<{ count : number, money : number }> = await queryCartNumAndMoney(); const cartNumAndMoney : Response<{ count : number, money : number }> = await queryCartNumAndMoney();
state.cartCount = cartNumAndMoney?.data?.count || 0; state.cartCount = cartNumAndMoney?.data?.count || 0;
state.cartMoney = cartNumAndMoney?.data?.money || 0; state.cartMoney = cartNumAndMoney?.data?.money || 0;
} }
/** 选择sku */ /** 选择sku */
const handleSelectSku = (id : number) => { const handleSelectSku = (id : number) => {
_useLoginStore.checkLogin(async () => { _useLoginStore.checkLogin(async () => {
let goodsDetail : any = null; let goodsDetail : any = null;
if (uni.getStorageSync(UserToken)) { if (uni.getStorageSync(UserToken)) {
goodsDetail = await queryGoodsDetailByToken({ goodsDetail = await queryGoodsDetailByToken({
id: id, id: id,
data: true, data: true,
}) })
} else { } else {
goodsDetail = await queryGoodsDetail({ goodsDetail = await queryGoodsDetail({
id: id, id: id,
data: true, data: true,
}) })
} }
state.goodsDetailData = goodsDetail.data; state.goodsDetailData = goodsDetail.data;
state.showSku = true; state.showSku = true;
}) })
} }
/** 底部按钮去结算 */ /** 底部按钮去结算 */
const handleGoPay = () => { const handleGoPay = () => {
_useLoginStore.checkLogin(() => { _useLoginStore.checkLogin(() => {
handleRouteSwitchTab(RouteSwitchTabEnum.cart); handleRouteSwitchTab(RouteSwitchTabEnum.cart);
}); });
} }
/** 添加购物车 */ /** 添加购物车 */
async function onAddCart({ productId, nums } : any) { async function onAddCart({ productId, nums } : any) {
const addCart : Response<number> = await queryAddCart({ const addCart : Response<number> = await queryAddCart({
productId, productId,
nums, nums,
type: AddCartEnum.add, type: AddCartEnum.add,
}); });
if (addCart.status) { if (addCart.status) {
handleShowToast(addCart.msg, 'success'); handleShowToast(addCart.msg, 'success');
/** 添加成功后,重新获取购物车数量和价格 */ /** 添加成功后,重新获取购物车数量和价格 */
await getCartNumAndMoney(); await getCartNumAndMoney();
/** 关闭sku弹框 */ /** 关闭sku弹框 */
handleChangePopup(false); handleChangePopup(false);
} else { } else {
handleShowToast(addCart.msg); handleShowToast(addCart.msg);
} }
} }
/** 立即购买 */ /** 立即购买 */
async function onBuyNow({ productId, nums } : any) { async function onBuyNow({ productId, nums } : any) {
const addCart : Response<number> = await queryAddCart({ const addCart : Response<number> = await queryAddCart({
productId, productId,
nums, nums,
type: AddCartEnum.buy, type: AddCartEnum.buy,
cartType: PaymentTypeEnum.common, cartType: PaymentTypeEnum.common,
}); });
if (addCart.status) { if (addCart.status) {
handleRouteNavigateTo(`/pages/order/submit/submit?cartIds=${addCart.data}`) handleRouteNavigateTo(`/pages/order/submit/submit?cartIds=${addCart.data}`)
/** 关闭sku弹框 */ /** 关闭sku弹框 */
handleChangePopup(false); handleChangePopup(false);
} else { } else {
handleShowToast(addCart.msg); handleShowToast(addCart.msg);
} }
} }
/** sku弹框显示隐藏 */ /** sku弹框显示隐藏 */
const handleChangePopup = (show : boolean) => { const handleChangePopup = (show : boolean) => {
state.showSku = show; state.showSku = show;
} }
/** 切换左侧tab */ /** 切换左侧tab */
const hanldeChangeLeftTab = (item : CategoriesType) => { const hanldeChangeLeftTab = (item : CategoriesType) => {
if (state.leftTabId != item.id) { if (state.leftTabId != item.id) {
state.leftTabId = item.id; state.leftTabId = item.id;
state.catId = item.id; state.catId = item.id;
state.rightTabList = item?.child; state.rightTabList = item?.child;
handleResetGoodsList(); handleResetGoodsList();
} }
} }
/** 切换右侧tab */ /** 切换右侧tab */
const hanldeChangeRightTab = (item : CategoriesType) => { const hanldeChangeRightTab = (item : CategoriesType) => {
state.catId = item.id; state.catId = item.id;
handleResetGoodsList(); handleResetGoodsList();
} }
/** 组合商品数据传入组件 */ /** 组合商品数据传入组件 */
const hanldeCombinationGoodsData = (item : any) => { const hanldeCombinationGoodsData = (item : any) => {
return { return {
id: item.id, id: item.id,
image: item.image, image: item.image,
name: item.name, name: item.name,
brief: item.brief, brief: item.brief,
price: item.price, price: item.price,
mktprice: item.mktprice, mktprice: item.mktprice,
isRecommend: item.isRecommend, isRecommend: item.isRecommend,
isHot: item.isHot, isHot: item.isHot,
} }
} }
/** 加载下一页数据 */ /** 加载下一页数据 */
const handleScrolltolower = () => { const handleScrolltolower = () => {
if (state.totalPages > state.page) { if (state.totalPages > state.page) {
state.page++; state.page++;
getGoodsPageList(); getGoodsPageList();
} }
} }
/** 重置商品列表数据 */ /** 重置商品列表数据 */
const handleResetGoodsList = () => { const handleResetGoodsList = () => {
state.page = 1; state.page = 1;
state.goodsList = []; state.goodsList = [];
getGoodsPageList(); getGoodsPageList();
} }
const hanldeClickGoods = (item : GoodsType) => { const hanldeClickGoods = (item : GoodsType) => {
uni.navigateTo({ uni.navigateTo({
url: `/pages/goods/detail?id=${item.id}` url: `/pages/goods/detail?id=${item.id}`
}) })
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import './classify-four.scss'; @import './classify-four.scss';
</style> </style>

View File

@@ -1,72 +1,74 @@
<template> <template>
<view class="classify-box" :style="{height: `${height}px`}"> <view class="classify-box" :style="{height: `${height}px`}">
<view class="classify-left"> <view class="classify-left">
<scroll-view class="scroll-view" enable-flex :scroll-y="true"> <scroll-view class="scroll-view" enable-flex :scroll-y="true">
<view :class="['item', { 'on': state.leftTabId === item.id }]" v-for="item, index in props.data" <view :class="['item', { 'on': state.leftTabId === item.id }]" v-for="item, index in props.data"
:key="index" @click="hanldeChangeLeftTab(item)"> :key="index" @click="hanldeChangeLeftTab(item)">
{{ item.name }} {{ item.name }}
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
<view class="classify-right"> <view class="classify-right">
<scroll-view class="scroll-view" enable-flex :scroll-y="true"> <scroll-view class="scroll-view" enable-flex :scroll-y="true">
<view class="advert-box radius-15"> <view class="advert-box radius-15">
<coreshop-advert :code="advertPosition.goodsClassifyBanner"></coreshop-advert> <coreshop-advert :code="advertPosition.goodsClassifyBanner"></coreshop-advert>
</view> </view>
<view class="data-box" v-if="state.list.length > 0"> <view class="data-box" v-if="state.list && state.list.length > 0">
<view class="item-box" v-for="item,index in state.list" :key="index" <view class="item-box" v-for="item,index in state.list" :key="index"
@click="handleGoCategory(item.id)"> @click="handleGoCategory(item.id)">
<image class="img" :src="item.imageUrl"></image> <image class="img" :src="item.imageUrl"></image>
<view class="name">{{ item.name }}</view> <view class="name">{{ item.name }}</view>
</view> </view>
</view> </view>
<view v-else> <view v-else>
<coreshop-empty></coreshop-empty> <coreshop-empty></coreshop-empty>
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
</view> </view>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, watch } from 'vue'; import { reactive, watch } from 'vue';
import type { CategoriesType } from '@/core/models'; import type { CategoriesType } from '@/core/models';
import { advertPosition } from '@/core/consts'; import { advertPosition } from '@/core/consts';
import { handleRouteNavigateTo } from '@/core/utils'; import { handleRouteNavigateTo } from '@/core/utils';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
data : Array<CategoriesType>, data : Array<CategoriesType>,
height : number, height : number,
}>(), { }>(), {
data: () => [], data: () => [],
height: 0, height: 0,
}); });
const state = reactive<{ const state = reactive<{
leftTabId : number; leftTabId : number;
list : Array<CategoriesType> list : Array<CategoriesType>
}>({ }>({
leftTabId: 0, leftTabId: 0,
list: [], list: [],
}); });
watch(() => props.data, (newVal : Array<CategoriesType>) => { watch(() => props.data, (newVal : Array<CategoriesType>) => {
state.leftTabId = newVal[0]?.id; if(newVal){
state.list = newVal[0]?.child; state.leftTabId = newVal[0]?.id;
}) state.list = newVal[0]?.child;
}
})
const hanldeChangeLeftTab = (item : CategoriesType) => { const hanldeChangeLeftTab = (item : CategoriesType) => {
if (state.leftTabId != item.id) { if (state.leftTabId != item.id) {
state.leftTabId = item.id; state.leftTabId = item.id;
state.list = item?.child; state.list = item?.child;
} }
} }
const handleGoCategory = (id : number) => { const handleGoCategory = (id : number) => {
handleRouteNavigateTo(`/pages/category/category?catId=${id}`) handleRouteNavigateTo(`/pages/category/category?catId=${id}`)
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import './classify-three.scss'; @import './classify-three.scss';
</style> </style>

View File

@@ -1,115 +1,118 @@
<template> <template>
<coreshop-page :isBack="false" bgColor="rgba(0,0,0,0)" :isShowStatusBarHeight="false" showLoginModalDom <coreshop-page :isBack="false" bgColor="rgba(0,0,0,0)" :isShowStatusBarHeight="false" showLoginModalDom
needLoadingPage :loadingPage="loading"> needLoadingPage :loadingPage="loading">
<view class="layout-classify-page"> <view class="layout-classify-page">
<!-- #ifndef MP-ALIPAY --> <!-- #ifndef MP-ALIPAY -->
<uv-navbar bgColor="#EEF3F7" :height="menuButtonHeight+'px'"> <uv-navbar bgColor="#EEF3F7" :height="menuButtonHeight+'px'">
<template #left> <template #left>
<!-- #ifdef MP --> <!-- #ifdef MP -->
<view class="search-box" style="max-width: 500rpx;"> <view class="search-box" style="max-width: 500rpx;">
<!-- #endif --> <!-- #endif -->
<!-- #ifdef APP --> <!-- #ifdef APP -->
<view class="search-box" style="width: 700rpx;"> <view class="search-box" style="width: 700rpx;">
<!-- #endif --> <!-- #endif -->
<view class="page-name">分类</view> <view class="page-name">分类</view>
<uv-input v-model="state.keyWord" @confirm="handleSearch" shape="circle" <uv-input v-model="state.keyWord" @confirm="handleSearch" shape="circle"
placeholder="请输入关键词" prefixIcon="search" placeholder="请输入关键词" prefixIcon="search"
:customStyle="{ 'background-color': '#fff' ,'padding':'3px 9px'}" :customStyle="{ 'background-color': '#fff' ,'padding':'3px 9px'}"
prefixIconStyle="font-size: 22px;color: #909399"> prefixIconStyle="font-size: 22px;color: #909399">
<template #suffix> <template #suffix>
<view class="search-tit" @click.stop="handleSearch">搜索</view> <view class="search-tit" @click.stop="handleSearch">搜索</view>
</template> </template>
</uv-input> </uv-input>
</view> </view>
</template> </template>
</uv-navbar> </uv-navbar>
<!-- #endif --> <!-- #endif -->
<view class="content-box" :style="{'height': `${state.height}px` }"> <view class="content-box" :style="{'height': `${state.height}px` }">
<classifyOne v-if="shopConfigStore.config.cateStyle == GoodsListEnum.one" :data="state.categoriesList"> <classifyOne v-if="shopConfigStore.config.cateStyle == GoodsListEnum.one" :data="state.categoriesList">
</classifyOne> </classifyOne>
<classifyTwo v-else-if="shopConfigStore.config.cateStyle == GoodsListEnum.two" <classifyTwo v-else-if="shopConfigStore.config.cateStyle == GoodsListEnum.two"
:data="state.categoriesList"> :data="state.categoriesList">
</classifyTwo> </classifyTwo>
<classifyThree v-else-if="shopConfigStore.config.cateStyle == GoodsListEnum.three" <classifyThree v-else-if="shopConfigStore.config.cateStyle == GoodsListEnum.three"
:data="state.categoriesList" :height="state.height"></classifyThree> :data="state.categoriesList" :height="state.height"></classifyThree>
<classifyFour v-else-if="shopConfigStore.config.cateStyle == GoodsListEnum.four" <classifyFour v-else-if="shopConfigStore.config.cateStyle == GoodsListEnum.four"
:data="state.categoriesList" :height="state.height"> :data="state.categoriesList" :height="state.height">
</classifyFour> </classifyFour>
<classifyFive v-else-if="shopConfigStore.config.cateStyle == GoodsListEnum.five" <classifyFive v-else-if="shopConfigStore.config.cateStyle == GoodsListEnum.five"
:data="state.categoriesList" :height="state.height" :statusBarHeight="statusBarHeight"> :data="state.categoriesList" :height="state.height" :statusBarHeight="statusBarHeight">
</classifyFive> </classifyFive>
</view> </view>
</view> </view>
</coreshop-page> </coreshop-page>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, reactive, watchEffect, ref } from 'vue'; import { onMounted, reactive, watchEffect, ref } from 'vue';
import { onHide, onPullDownRefresh } from '@dcloudio/uni-app'; import { onHide, onPullDownRefresh } from '@dcloudio/uni-app';
import { useShopConfigStore } from '@/core/store'; import { useShopConfigStore } from '@/core/store';
import { queryAllCategories } from '@/core/api'; import { queryAllCategories } from '@/core/api';
import { GoodsListEnum } from '@/core/enum'; import { GoodsListEnum } from '@/core/enum';
import { handleRouteNavigateTo } from '@/core/utils'; import { handleRouteNavigateTo } from '@/core/utils';
import { onClassifyPageHide } from '@/core/consts'; import { onClassifyPageHide, onClassifyPagePullDownRefresh } from '@/core/consts';
import type { Response, ShopConfigStoreType, CategoriesType } from '@/core/models'; import type { Response, ShopConfigStoreType, CategoriesType } from '@/core/models';
import classifyOne from './classify-page/classify-one/classify-one.vue'; import classifyOne from './classify-page/classify-one/classify-one.vue';
import classifyTwo from './classify-page/classify-two/classify-two.vue'; import classifyTwo from './classify-page/classify-two/classify-two.vue';
import classifyThree from './classify-page/classify-three/classify-three.vue'; import classifyThree from './classify-page/classify-three/classify-three.vue';
import classifyFour from './classify-page/classify-four/classify-four.vue'; import classifyFour from './classify-page/classify-four/classify-four.vue';
import classifyFive from './classify-page/classify-five/classify-five.vue'; import classifyFive from './classify-page/classify-five/classify-five.vue';
import { useLoadingFn, useSystemInfo } from '@/core/hooks'; import { useLoadingFn, useSystemInfo } from '@/core/hooks';
// 获取项目配置 // 获取项目配置
const shopConfigStore : ShopConfigStoreType = useShopConfigStore(); const shopConfigStore : ShopConfigStoreType = useShopConfigStore();
// 获取自定义导航栏高度 // 获取自定义导航栏高度
const { statusBarHeight, systemInfo, menuButtonHeight } = useSystemInfo(); const { statusBarHeight, systemInfo, menuButtonHeight } = useSystemInfo();
const loading = ref(true); const loading = ref(true);
const state = reactive<{ const state = reactive<{
categoriesList : Array<CategoriesType>, categoriesList : Array<CategoriesType>,
height : number, height : number,
keyWord : string; keyWord : string;
}>({ }>({
categoriesList: [], categoriesList: [],
height: 0, height: 0,
keyWord: "", keyWord: "",
}) })
const handleuAllCategories = useLoadingFn(getAllCategories, loading); const handleuAllCategories = useLoadingFn(getAllCategories, loading);
onMounted(async () => { onMounted(async () => {
handleuAllCategories(); handleuAllCategories();
}) })
watchEffect(() => { watchEffect(() => {
state.height = systemInfo.value.windowHeight - statusBarHeight.value ; state.height = systemInfo.value.windowHeight - statusBarHeight.value;
}) })
onHide(() => { onHide(() => {
/** 触发自定义onhide事件让后代组件监听页面是关闭 */ /** 触发自定义onhide事件让后代组件监听页面是关闭 */
uni.$emit(onClassifyPageHide); uni.$emit(onClassifyPageHide);
}); });
onPullDownRefresh(async () => { onPullDownRefresh(async () => {
await handleuAllCategories() /** 触发onPullDownRefresh事件让后代组件监听页面是下拉刷新 */
uni.stopPullDownRefresh(); uni.$emit(onClassifyPagePullDownRefresh);
}); state.categoriesList = [];
await handleuAllCategories()
uni.stopPullDownRefresh();
});
/** 获取购物车数量价格 */ /** 获取购物车数量价格 */
async function getAllCategories() { async function getAllCategories() {
const allCategories : Response<Array<CategoriesType>> = await queryAllCategories(); const allCategories : Response<Array<CategoriesType>> = await queryAllCategories();
state.categoriesList = allCategories.data || []; state.categoriesList = allCategories.data || [];
} }
/** 搜索 */ /** 搜索 */
const handleSearch = () => { const handleSearch = () => {
handleRouteNavigateTo(`/pages/category/category?key=${state.keyWord}`); handleRouteNavigateTo(`/pages/category/category?key=${state.keyWord}`);
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import './classify.scss'; @import './classify.scss';
</style> </style>

View File

@@ -1,39 +1,39 @@
<template> <template>
<swiper class="swiper m-b-25" v-if="props.data.list.length > 0" :vertical="false" :indicator-dots="props.dotsSelect" <swiper class="swiper m-b-25" v-if="props.data.list.length > 0" :vertical="false" :indicator-dots="props.dotsSelect"
:autoplay="props.autoplaySelect" :interval="props.data.duration" :circular="props.circularSelect" :autoplay="props.autoplaySelect" :interval="props.data.duration" :circular="props.circularSelect"
:indicator-color="props.indicatorColor" :indicator-active-color="props.indicatorColorActive"> :indicator-color="props.indicatorColor" :indicator-active-color="props.indicatorColorActive">
<swiper-item v-for="item, index in props.data.list" :key="index" @click="hanldeClickImage(item)"> <swiper-item v-for="item, index in props.data.list" :key="index" @click="hanldeClickImage(item)">
<image class="swiper-img" :src="item.image"></image> <image class="swiper-img" :src="item.image"></image>
</swiper-item> </swiper-item>
</swiper> </swiper>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { PageConfigItemsImgSlideType } from '@/core/models'; import type { PageConfigItemsImgSlideType } from '@/core/models';
import { handleAdvertiseDetail } from '@/core/utils'; import { handleAdvertiseDetail } from '@/core/utils';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
data : any, data ?: any,
dotsSelect : boolean, dotsSelect ?: boolean,
autoplaySelect : boolean, autoplaySelect ?: boolean,
intervalSelect : number, intervalSelect ?: number,
circularSelect : boolean, circularSelect ?: boolean,
indicatorColor : string, indicatorColor ?: string,
indicatorColorActive : string, indicatorColorActive ?: string,
}>(), { }>(), {
data: {}, data: {},
dotsSelect: true, dotsSelect: true,
autoplaySelect: true, autoplaySelect: true,
intervalSelect: 3000, intervalSelect: 3000,
circularSelect: true, circularSelect: true,
indicatorColor: '#EEF2F6', indicatorColor: '#EEF2F6',
indicatorColorActive: '#E74435' indicatorColorActive: '#E74435'
}); });
const hanldeClickImage = (item : PageConfigItemsImgSlideType) => { const hanldeClickImage = (item : PageConfigItemsImgSlideType) => {
handleAdvertiseDetail(Number(item.linkType), item.linkValue); handleAdvertiseDetail(Number(item.linkType), item.linkValue);
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "./home-swiper.scss"; @import "./home-swiper.scss";
</style> </style>

View File

@@ -13,7 +13,7 @@
</view> </view>
</view> </view>
<view class="title-box" v-if="state.formInfo?.description"> <view class="title-box" v-if="state.formInfo?.description">
<view calss="title">{{ state.formInfo?.description }}1</view> <view calss="title">{{ state.formInfo?.description }}</view>
</view> </view>
<!-- 表单主体内容 --> <!-- 表单主体内容 -->
<view class="form-content"> <view class="form-content">