feat: 热门推荐页

This commit is contained in:
jqtmviyu 2025-04-23 15:37:38 +08:00
parent 21b9783bf8
commit 8f538dd197
4 changed files with 263 additions and 4 deletions

View File

@ -51,7 +51,7 @@
{
"path": "pages/hot/hot",
"style": {
"navigationBarTitleText": "hot"
"navigationBarTitleText": "热门推荐"
}
},
{

View File

@ -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
View 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
View 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[]
}