feat: ✨ 热门推荐页
This commit is contained in:
parent
21b9783bf8
commit
8f538dd197
@ -51,7 +51,7 @@
|
||||
{
|
||||
"path": "pages/hot/hot",
|
||||
"style": {
|
||||
"navigationBarTitleText": "hot"
|
||||
"navigationBarTitleText": "热门推荐"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1,7 +1,225 @@
|
||||
<template>
|
||||
<view class="hot">hot</view>
|
||||
<view class="viewport">
|
||||
<!-- 推荐封面图 -->
|
||||
<view class="cover">
|
||||
<image :src="bannerPic"></image>
|
||||
</view>
|
||||
<template>
|
||||
<!-- 推荐选项 -->
|
||||
<view class="tabs">
|
||||
<text
|
||||
:class="['text', { active: index === actived }]"
|
||||
v-for="(subTypeItem, index) in subTypes"
|
||||
:key="subTypeItem.id"
|
||||
@tap="actived = index"
|
||||
>{{ subTypeItem.title }}</text
|
||||
>
|
||||
</view>
|
||||
<!-- 推荐列表 -->
|
||||
<scroll-view
|
||||
:scroll-y="true"
|
||||
class="scroll-view"
|
||||
@scrolltolower="onScrollToLower"
|
||||
v-for="(subTypeItem, index) in subTypes"
|
||||
v-show="actived === index"
|
||||
:key="subTypeItem.id"
|
||||
>
|
||||
<view class="goods">
|
||||
<navigator
|
||||
hover-class="none"
|
||||
class="navigator"
|
||||
v-for="goodItem in subTypeItem.goodsItems.items"
|
||||
:key="goodItem.id"
|
||||
:url="`/pages/goods/goods?id=${goodItem.id}`"
|
||||
>
|
||||
<image class="thumb" :src="goodItem.picture"></image>
|
||||
<view class="name ellipsis">{{ goodItem.desc }}</view>
|
||||
<view class="price">
|
||||
<text class="symbol">¥</text>
|
||||
<text class="number">{{ goodItem.price }}</text>
|
||||
</view>
|
||||
</navigator>
|
||||
</view>
|
||||
<view class="loading-text">{{
|
||||
subTypeItem.goodsItems.page === subTypeItem.goodsItems.pages
|
||||
? '没有更多数据~'
|
||||
: '正在加载...'
|
||||
}}</view>
|
||||
</scroll-view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup></script>
|
||||
<script setup lang="ts">
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { getHotRecommend } from '@/services/hot'
|
||||
import type { SubTypeItem } from '@/types/hot'
|
||||
import { ref } from 'vue'
|
||||
|
||||
<style lang="scss"></style>
|
||||
// 热门推荐页 标题和url
|
||||
const hotMap = {
|
||||
'1': { title: '特惠推荐', url: '/hot/preference' },
|
||||
'2': { title: '爆款推荐', url: '/hot/inVogue' },
|
||||
'3': { title: '一站买全', url: '/hot/oneStop' },
|
||||
'4': { title: '新鲜好物', url: '/hot/new' },
|
||||
}
|
||||
|
||||
// uni-app获取路由参数
|
||||
const query = defineProps<{
|
||||
type: string
|
||||
}>()
|
||||
|
||||
// 热门类型
|
||||
const currHot = hotMap[query.type as keyof typeof hotMap]
|
||||
// 动态设置标题
|
||||
uni.setNavigationBarTitle({ title: currHot!.title })
|
||||
|
||||
// 推荐封面图
|
||||
const bannerPic = ref('')
|
||||
// 分类列表
|
||||
const subTypes = ref<SubTypeItem[]>([])
|
||||
|
||||
// 当前选中的分类id
|
||||
const actived = ref(0)
|
||||
|
||||
// 获取热门商品, 不传subType, 获取所有分类第一页
|
||||
const getRecommend = async () => {
|
||||
const res = await getHotRecommend(currHot!.url, {
|
||||
page: import.meta.env.DEV ? 33 : 1,
|
||||
pageSize: 10,
|
||||
})
|
||||
bannerPic.value = res.result.bannerPicture
|
||||
subTypes.value = res.result.subTypes
|
||||
}
|
||||
|
||||
// 滚动到底部
|
||||
const onScrollToLower = async () => {
|
||||
// 只追加当前tab的数据
|
||||
const subTypeId = subTypes.value[actived.value].id
|
||||
const { page, pages, pageSize } = subTypes.value[actived.value].goodsItems
|
||||
// 没有更多数据
|
||||
if (page === pages) {
|
||||
uni.showToast({
|
||||
title: '没有更多数据~',
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
const nextPage = page + 1
|
||||
// 接口被复用了, 没有传的subType, 没有返回 goodsItems 数据
|
||||
const res = await getHotRecommend(currHot!.url, {
|
||||
subType: subTypeId,
|
||||
page: nextPage,
|
||||
pageSize,
|
||||
})
|
||||
// 追加数据
|
||||
subTypes.value[actived.value].goodsItems.items.push(
|
||||
...res.result.subTypes[actived.value].goodsItems.items,
|
||||
)
|
||||
subTypes.value[actived.value].goodsItems.page = nextPage
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
getRecommend()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
height: 100%;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.viewport {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding: 180rpx 0 0;
|
||||
position: relative;
|
||||
}
|
||||
.cover {
|
||||
width: 750rpx;
|
||||
height: 225rpx;
|
||||
border-radius: 0 0 40rpx 40rpx;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.scroll-view {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
.tabs {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
height: 100rpx;
|
||||
line-height: 90rpx;
|
||||
margin: 0 20rpx;
|
||||
font-size: 28rpx;
|
||||
border-radius: 10rpx;
|
||||
box-shadow: 0 4rpx 5rpx rgba(200, 200, 200, 0.3);
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
z-index: 9;
|
||||
.text {
|
||||
margin: 0 20rpx;
|
||||
position: relative;
|
||||
}
|
||||
.active {
|
||||
&::after {
|
||||
content: '';
|
||||
width: 40rpx;
|
||||
height: 4rpx;
|
||||
transform: translate(-50%);
|
||||
background-color: #27ba9b;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 24rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.goods {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
padding: 0 20rpx 20rpx;
|
||||
.navigator {
|
||||
width: calc(50% - 50rpx);
|
||||
padding: 20rpx;
|
||||
margin-top: 20rpx;
|
||||
border-radius: 10rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
.thumb {
|
||||
width: 305rpx;
|
||||
height: 305rpx;
|
||||
}
|
||||
.name {
|
||||
height: 88rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
.price {
|
||||
line-height: 1;
|
||||
color: #cf4444;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
.symbol {
|
||||
font-size: 70%;
|
||||
}
|
||||
.decimal {
|
||||
font-size: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
padding: 20rpx 0 50rpx;
|
||||
}
|
||||
</style>
|
||||
|
18
src/services/hot.ts
Normal file
18
src/services/hot.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { http } from '@/utils/http'
|
||||
import type { PageParams, PageResult } from '@/types/global'
|
||||
import type { HotResult } from '@/types/hot'
|
||||
|
||||
type HotParams = PageParams & {
|
||||
// 推荐列表 Tab 项的 id, 默认查询全部 Tab 项的第 1 页数据
|
||||
subType?: string
|
||||
}
|
||||
/**
|
||||
* 获取热门推荐
|
||||
*/
|
||||
export const getHotRecommend = (url: string, data: HotParams) => {
|
||||
return http<HotResult>({
|
||||
url,
|
||||
method: 'GET',
|
||||
data,
|
||||
})
|
||||
}
|
23
src/types/hot.d.ts
vendored
Normal file
23
src/types/hot.d.ts
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
import type { PageResult, GoodsItem } from './global'
|
||||
|
||||
/** 热门推荐-子类选项 */
|
||||
export type SubTypeItem = {
|
||||
/** 子类id */
|
||||
id: string
|
||||
/** 子类标题 */
|
||||
title: string
|
||||
/** 子类对应的商品集合 */
|
||||
goodsItems: PageResult<GoodsItem>
|
||||
}
|
||||
|
||||
/** 热门推荐 */
|
||||
export type HotResult = {
|
||||
/** id信息 */
|
||||
id: string
|
||||
/** 活动图片 */
|
||||
bannerPicture: string
|
||||
/** 活动标题 */
|
||||
title: string
|
||||
/** 子类选项 */
|
||||
subTypes: SubTypeItem[]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user