Refactor(首页):改版重构-界面完成

This commit is contained in:
lifizer
2024-07-31 16:36:13 +08:00
parent 37fa7fab05
commit b9c3ff756c
3 changed files with 466 additions and 143 deletions
+160
View File
@@ -0,0 +1,160 @@
<template>
<view class="xdd-product-item" @click="viewHandle(item)">
<view class="focus-img">
<image
:src="item[imageKey]"
class="img"
/>
<image
v-if="item.isOldBrand"
:src="webUrl + '/home/old-mark'"
class="mark-img"
/>
<image
v-if="item.isOldBrand"
:src="webUrl + '/home/mark-land.png'"
class="mark-img"
/>
<image
v-if="item.isCountyFamous"
:src="webUrl + '/home/qixian-mark.png'"
class="mark-img"
/>
</view>
<view class="info-wrap">
<view class="name more-t">
{{ item.storeName }}
</view>
<view class="desc">
{{ item.desc || '古法熬制·甄选原料' }}
</view>
<view class="coupon">
<view class="tag">券</view>
<view class="tag">5元无门槛</view>
</view>
<view class="price-wrap">
<view class="price">
<text class="price-txt price-red">¥{{ item.price }}</text>
</view>
<view class="btn">
<image
:src="webUrl + '/home/icon-cart.png'"
class="img"
/>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'XddProductItem',
props: {
item: {
type: Object,
default: () => {
return {}
}
},
imageKey: {
type: String,
default: 'image'
}
},
data() {
return {
webUrl: this.$VUE_APP_RESOURCES_URL
}
},
methods: {
viewHandle(item) {
this.$emit('view', item)
}
}
}
</script>
<style lang="less">
.xdd-product-item {
border-radius: 20rpx;
background-color: #fff;
overflow: hidden;
.focus-img {
position: relative;
.img {
position: relative;
z-index: 2;
display: block;
width: 344rpx;
height: 344rpx;
border-radius: 20rpx;
}
.mark-img {
position: absolute;
top: 0;
right: 0;
z-index: 3;
display: block;
width: 84rpx;
height: 74rpx;
}
}
.info-wrap {
padding: 12rpx;
.name {
font-size: 28rpx;
line-height: 40rpx;
color: #333;
}
.desc {
padding: 10rpx 0;
color: #FFC543;
font-size: 24rpx;
}
.coupon {
display: flex;
.tag + .tag {
margin: 0 0 0 -1rpx;
}
.tag {
height: 32rpx;
padding: 0 6rpx;
border-radius: 8rpx;
border: 1rpx solid #C52733;
color: #C52733;
line-height: 32rpx;
font-size: 10px;
}
}
.price-wrap {
display: flex;
justify-content: space-between;
align-items: flex-end;
padding: 10rpx 0 0 0;
.price {
font-size: 24rpx;
line-height: 40rpx;
.price-txt {
font-size: 40rpx;
font-weight: bold;
}
}
.price-red {
margin: 0 10rpx 0 0;
color: #C52733;
}
.price-grey {
color: #C4C4C4;
}
.btn {
.img {
display: block;
width: 48rpx;
height: 48rpx;
}
}
}
}
}
</style>
+19 -2
View File
@@ -25,9 +25,14 @@
@click="gotoPage(item.url, item.type, item.index)" @click="gotoPage(item.url, item.type, item.index)"
> >
<view class="img-wrap"> <view class="img-wrap">
<!-- 预加载两张图片,可以在点击切换的时候不闪屏 -->
<image <image
:src="currIndex === item.index ? item.onIcon : item.offIcon" :src="item.onIcon"
class="img" class="img on"
/>
<image
:src="item.offIcon"
class="img off"
/> />
</view> </view>
<view class="name">{{ item.name }}</view> <view class="name">{{ item.name }}</view>
@@ -144,6 +149,12 @@ export default {
width: 44rpx; width: 44rpx;
height: 44rpx; height: 44rpx;
margin: 0 auto; margin: 0 auto;
&.on {
display: none;
}
&.off {
display: block;
}
} }
} }
.name { .name {
@@ -158,6 +169,12 @@ export default {
.name { .name {
color: #C52733; color: #C52733;
} }
.on {
display: block;
}
.off {
display: none;
}
} }
} }
} }
+266 -120
View File
@@ -1,5 +1,28 @@
<template> <template>
<view class="tabbar-page"> <view class="tabbar-page">
<view
:style="{
'padding-top': statusBarHeight + 'px',
'padding-right': rightDistance + 'px'
}"
:class="scrollTop > 40 ? 'blur' : ''"
class="fix-header"
@click="goGoodSearch"
>
<view class="location">
昆明
<image
:src="webUrl + '/home/icon-location.png'"
class="icon"
/>
</view>
<view class="search-wrap">
<image
:src="webUrl + '/home/icon-search.png'"
class="icon"
/>
</view>
</view>
<view class="slider-banner"> <view class="slider-banner">
<swiper <swiper
v-if="banner.length > 0" v-if="banner.length > 0"
@@ -45,19 +68,24 @@
</view> </view>
</view> </view>
<!-- 千县名品和地标好物 --> <!-- 千县名品和地标好物 -->
<view class="land-famous-wrap"> <view
<view class="pic-wrap"> v-if="landmarkGoodsImage.image || countyFamousImage.image"
class="land-famous-wrap"
>
<view v-if="countyFamousImage.image" class="pic-wrap">
<image <image
:src="webUrl + '/home/land-pic.png'" :src="countyFamousImage.image"
mode="heightFix" mode="heightFix"
class="img" class="img"
@click="landAndFamousItemClickHandle(countyFamousImage)"
/> />
</view> </view>
<view class="pic-wrap"> <view v-if="landmarkGoodsImage.image" class="pic-wrap">
<image <image
:src="webUrl + '/home/famous-pic.png'" :src="landmarkGoodsImage.image"
mode="heightFix" mode="heightFix"
class="img" class="img"
@click="landAndFamousItemClickHandle(landmarkGoodsImage)"
/> />
</view> </view>
</view> </view>
@@ -102,78 +130,77 @@
<view class="bast-list"> <view class="bast-list">
<view class="bast-list-left"> <view class="bast-list-left">
<view <view
v-for="(item,index) in bastLeftList" v-for="(item, index) in bastLeftList"
:key="index" :key="index"
class="item flex" class="item flex"
> >
<template v-if="item.storeName === 'swiper'"> <view
<swiper class="item bannar-swiper" autoplay circular> v-if="item.type === 'hotel'"
<swiper-item v-for="swipe in bannerList" :key="swipe"> class="hotel-list-wrap"
>
<image <image
:src="swipe.pic" :src="webUrl + '/home/hotel-list-bg.png'"
mode="aspectFit" mode="widthFix"
@click="goGoodsConByProductID(swipe)" class="bg"
/> />
</swiper-item> <view class="list">
</swiper> <view
</template> v-for="(hotelItem, hotelIndex) in item.list"
<template v-else> :key="hotelIndex"
<image class="hotel-item"
:src="item.image" @click="hotelItemClickHandle(hotelItem)"
class="top-img" >
mode="scaleToFill" <image :src="webUrl + '/home/home-number' + (hotelIndex + 1) + '.png'" class="mark" />
@click="goGoodsCon(item)" <image :src="webUrl + '/home/icon-hotel-btn'" class="btn" />
/> <image :src="hotelItem.logo" class="logo" />
<view class="content" @click="goGoodsCon(item)"> <view class="info">
<view class="title more-t">{{ item.storeName }}</view> <view class="name one-t">{{ hotelItem.name }}</view>
<view class="price flex"> <view class="desc more-t">{{ hotelItem.content }}</view>
<text class="red">¥{{ item.price }}</text>
<text
v-if="item.productPrice"
class="gray"
>¥{{ item.productPrice }}
</text>
</view> </view>
</view> </view>
</template> </view>
</view>
<xdd-product-item
v-else
:item="item"
@view="goGoodsCon(item)"
/>
</view> </view>
</view> </view>
<view class="bast-list-right"> <view class="bast-list-right">
<view <view
v-for="(item,index) in bastRightList" v-for="(item, index) in bastRightList"
:key="index" :key="index"
class="item flex" class="item flex"
> >
<template v-if="item.storeName === 'swiper'"> <view
<swiper class="item bannar-swiper" autoplay circular> v-if="item.type === 'swiper'"
<swiper-item v-for="swipe in bannerList" :key="swipe"> class="swiper-wrap"
>
<swiper
class="swiper"
circular
autoplay
:interval="3000"
>
<swiper-item
v-for="(swiperItem, swiperIndex) in item.list"
:key="swiperIndex"
>
<image <image
:src="swipe.pic" :src="swiperItem.image"
mode="aspectFit" mode="scaleToFill"
@click="goGoodsConByProductID(swipe)" class="swiper-img"
@click="goHomeStay(swiperItem)"
/> />
</swiper-item> </swiper-item>
</swiper> </swiper>
</template> </view>
<template v-else> <xdd-product-item
<image v-else
:src="item.image" :item="item"
class="top-img" @view="goGoodsCon(item)"
mode="scaleToFill"
@click="goGoodsCon(item)"
/> />
<view class="content" @click="goGoodsCon(item)">
<view class="title more-t">{{ item.storeName }}</view>
<view class="price flex">
<text class="red">¥{{ item.price }}</text>
<text
v-if="item.productPrice"
class="gray"
>¥{{ item.productPrice }}
</text>
</view>
</view>
</template>
</view> </view>
</view> </view>
</view> </view>
@@ -218,7 +245,7 @@
<script> <script>
import XddTabbar from '@/components/xdd-tabbar' import XddTabbar from '@/components/xdd-tabbar'
import imgBox from '@/components/imageTypeSet/imagebox.vue' import XddProductItem from '@/components/xdd-product-item'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import { getCouponReceive } from '@/api/user' import { getCouponReceive } from '@/api/user'
import { getHomeData, getShareImage } from '@/api/public' import { getHomeData, getShareImage } from '@/api/public'
@@ -227,25 +254,28 @@ import { pageListenMixins } from '@/mixins/pageListenMixins'
export default { export default {
name: 'IndexPage', name: 'IndexPage',
components: { components: {
imgBox, XddTabbar,
XddTabbar XddProductItem
}, },
mixins: [pageListenMixins], mixins: [pageListenMixins],
data() { data() {
return { return {
webUrl: this.$VUE_APP_RESOURCES_URL, webUrl: this.$VUE_APP_RESOURCES_URL,
hotGoodsColumnWidth: '325rpx', // 状态栏高度
bgImgHeight: '20px', statusBarHeight: 20,
// 右侧距离
rightDistance: 10,
banner: [], banner: [],
menus: [], menus: [],
cityName: '', cityName: '',
// 尖货 // 地标好物
bastList: [], landmarkGoodsImage: {},
// 千县名品
countyFamousImage: {},
// 尖货推荐左侧 // 尖货推荐左侧
bastLeftList: [], bastLeftList: [],
// 尖货推荐右侧 // 尖货推荐右侧
bastRightList: [], bastRightList: [],
statusBarHeight: 64,
// 尖货推荐横幅 // 尖货推荐横幅
bannerList: [], bannerList: [],
// 分享图片 // 分享图片
@@ -268,17 +298,13 @@ export default {
uni.getSystemInfo({ uni.getSystemInfo({
success: (e) => { success: (e) => {
let statusBar = 0 let statusBar = 0
let customBar = 0
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
statusBar = e.statusBarHeight statusBar = e.statusBarHeight
const custom = uni.getMenuButtonBoundingClientRect() const custom = uni.getMenuButtonBoundingClientRect()
customBar = custom.bottom + custom.top - e.statusBarHeight _this.rightDistance = e.windowWidth - custom.left + 10
// #endif // #endif
_this.statusBarHeight = customBar // 状态栏高度
// 两列商品宽度 _this.statusBarHeight = statusBar
_this.hotGoodsColumnWidth = (e.screenWidth - uni.upx2px(90)) / 2 + 'px'
// 状态栏图片高度
_this.bgImgHeight = statusBar + 'px'
} }
}) })
}, },
@@ -297,26 +323,27 @@ export default {
imageUrl: this.shareAppImg imageUrl: this.shareAppImg
} }
}, },
onPullDownRefresh() {
uni.stopPullDownRefresh()
uni.navigateTo({
url: '/pkg-video/views/lottery'
})
},
onPageScroll(e) { onPageScroll(e) {
this.scrollTop = e.scrollTop this.scrollTop = e.scrollTop
}, },
methods: { methods: {
init() { init() {
getShareImage().then(({ data }) => this.shareAppImg = data)
sharpBannar().then(res => {
const { data } = res
this.bannerList = data.banner
this.getPageData()
})
},
getPageData() {
const _this = this const _this = this
getShareImage().then(({ data }) => _this.shareAppImg = data)
sharpBannar().then(response => {
_this.bannerList = response.data.banner
uni.showLoading({ title: '加载中' }) uni.showLoading({ title: '加载中' })
getHomeData().then(res => { getHomeData().then(res => {
const { data } = res const { data } = res
_this.$set(_this, 'banner', data.banner) _this.$set(_this, 'banner', data.banner)
_this.$set(_this, 'menus', data.menus) _this.$set(_this, 'menus', data.menus)
_this.$set(_this, 'landmarkGoodsImage', data.landmarkGoodsImage)
_this.$set(_this, 'countyFamousImage', data.countyFamousImage)
_this.$set(_this, 'oldUserPopup', data.oldUserPopup) _this.$set(_this, 'oldUserPopup', data.oldUserPopup)
_this.$set(_this, 'contentHomestay', data.contentHomestay) _this.$set(_this, 'contentHomestay', data.contentHomestay)
_this.$set(_this, 'contentFestival', data.contentFestival) _this.$set(_this, 'contentFestival', data.contentFestival)
@@ -324,9 +351,34 @@ export default {
_this.bastRightList = [] _this.bastRightList = []
for (let i = 0; i < data.bastList.length; i++) { for (let i = 0; i < data.bastList.length; i++) {
if (i % 2 === 0) { if (i % 2 === 0) {
if (i === 4 && data.hotelList.length > 0) {
_this.bastLeftList.push({
type: 'hotel',
list: data.hotelList
})
}
_this.bastLeftList.push(data.bastList[i]) _this.bastLeftList.push(data.bastList[i])
} }
if (i % 2 === 1) { if (i % 2 === 1) {
if (i === 3) {
_this.bastRightList.push({
type: 'swiper',
list: [
{
image: 'http://resource.xdd618.com/19/20240722/1721615384602_入口图8.jpg',
url: '/pkg_product/views/festival'
},
{
image: 'http://resource.xdd618.com/19/20240715/1721006994007_微信图片_20240715092549.jpg',
url: '/pkg_product/views/festival'
},
{
image: 'http://resource.xdd618.com/19/20240722/1721615384602_入口图8.jpg',
url: '/pkg_product/views/festival'
}
]
})
}
_this.bastRightList.push(data.bastList[i]) _this.bastRightList.push(data.bastList[i])
} }
} }
@@ -334,7 +386,6 @@ export default {
}).catch(() => { }).catch(() => {
uni.hideLoading() uni.hideLoading()
}) })
})
}, },
goRoll(item) { goRoll(item) {
if (item.uniapp_url) { if (item.uniapp_url) {
@@ -352,16 +403,6 @@ export default {
} }
}) })
}, },
goGoodsConByProductID(item, from) {
this.$yrouter.push({
path: '/pages/shop/GoodsCon/index',
query: {
id: item.productId,
activityId: item.id,
from
}
})
},
changeOldPopup(state) { changeOldPopup(state) {
this.isOldUser = state this.isOldUser = state
}, },
@@ -424,6 +465,19 @@ export default {
this.$global.levelJump(pageLevel, url, params) this.$global.levelJump(pageLevel, url, params)
} }
}, },
landAndFamousItemClickHandle(item) {
const url = item.url
if (!url) return
if (item.level === '1') {
uni.switchTab({ url })
}
if (item.level === '2') {
uni.navigateTo({ url })
}
},
hotelItemClickHandle(item) {
uni.navigateTo({ url: item.url })
},
setTopHandle() { setTopHandle() {
uni.pageScrollTo({ uni.pageScrollTo({
scrollTop: 0, scrollTop: 0,
@@ -491,7 +545,7 @@ export default {
.bast-title { .bast-title {
width: 312rpx; width: 312rpx;
height: 40rpx; height: 40rpx;
margin: 21rpx 0 21rpx 0; margin: 32rpx 0 0;
} }
.bannar-swiper { .bannar-swiper {
height: 534rpx; height: 534rpx;
@@ -509,34 +563,18 @@ export default {
} }
.item { .item {
position: relative; position: relative;
flex-direction: column;
border-radius: 20rpx;
margin: 21rpx 0 0 0; margin: 21rpx 0 0 0;
background: #fff; .swiper-wrap {
width: 100%;
border-radius: 20rpx;
overflow: hidden; overflow: hidden;
.top-img {
width: 343rpx;
height: 343rpx;
}
.content {
box-sizing: border-box;
padding: 10rpx 10rpx 20rpx;
.title {
color: #333;
font-size: 28rpx;
}
.price {
font-size: 32rpx;
.red {
color: #DA0000;
}
.gray {
margin-left: 16rpx;
text-decoration: line-through;
font-size: 20rpx;
line-height: 30rpx;
color: #C2C5CC;
} }
.swiper {
width: 100%;
height: 486rpx;
.swiper-img {
width: 100%;
height: 486rpx;
} }
} }
} }
@@ -584,7 +622,7 @@ export default {
top: 0; top: 0;
left: -21rpx; left: -21rpx;
z-index: 2; z-index: 2;
width: calc(100% + 42rpx); width: calc(100% + 40rpx);
height: 180rpx; height: 180rpx;
background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, #F0F0F0 40%, #F0F0F0 100%); background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, #F0F0F0 40%, #F0F0F0 100%);
content: " "; content: " ";
@@ -609,4 +647,112 @@ export default {
} }
} }
} }
.hotel-list-wrap {
position: relative;
width: 344rpx;
.bg {
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 2;
width: 100%;
}
.list {
position: relative;
z-index: 5;
padding: 100rpx 21rpx 21rpx 21rpx;
.hotel-item + .hotel-item {
margin: 21rpx 0 0 0;
}
.hotel-item {
position: relative;
display: flex;
align-items: center;
padding: 8rpx 16rpx 8rpx 8rpx;
border-radius: 16rpx;
background-color: #fff;
.mark {
position: absolute;
top: 8rpx;
left: 20rpx;
z-index: 5;
width: 26rpx;
height: 26rpx;
}
.btn {
position: absolute;
bottom: 8rpx;
right: 0;
z-index: 5;
width: 60rpx;
height: 22rpx;
}
.logo {
display: block;
width: 116rpx;
height: 116rpx;
border-radius: 16rpx;
}
.info {
width: calc(100% - 116rpx);
padding: 0 0 0 16rpx;
box-sizing: border-box;
.name {
font-size: 24rpx;
color: #333;
line-height: 40rpx;
}
.desc {
font-size: 20rpx;
color: #999;
line-height: 28rpx;
}
}
}
}
}
.fix-header {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 99;
display: flex;
align-items: center;
height: 44px;
padding-left: 21rpx;
line-height: 32px;
&.blur {
backdrop-filter: blur(5px);
}
.location {
display: flex;
align-items: center;
margin: -4px 20rpx 0 0;
color: #fff;
font-size: 32rpx;
.icon {
display: block;
width: 32rpx;
height: 32rpx;
margin: 0 0 0 10rpx;
}
}
.search-wrap {
display: flex;
align-items: center;
flex: 1;
height: 36px;
margin: -4px 0 0 0;
border-radius: 18px;
background-color: #fff;
.icon {
display: block;
width: 36rpx;
height: 36rpx;
margin: 0 0 0 20rpx;
}
}
}
</style> </style>