zdtap-uniapp-main/pagesMy/myAttention.vue

584 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page-content">
<scroll-view scroll-x class="bg-white nav">
<view class="flex text-center">
<view class="cu-item flex-sub tab" :class="tabCur == 0?'active cur':''" @tap="tabSelect" :data-id="0">
酒款
</view>
<view class="cu-item flex-sub tab" :class="tabCur == 1?'active cur':''" @tap="tabSelect" :data-id="1">
品牌
</view>
</view>
</scroll-view>
<view v-if="!isLogin" class="flex align-center justify-center" style="height: calc(100vh - 100rpx);">
<view class="flex flex-col align-center">
<text style="color: #747783;font-size: 28rpx;margin-bottom: 30rpx;">登录后查看我的关注</text>
<button class="cu-btn" style="color: #FFFFFF; background-color: #4E63E0;" @click="toLogin">去登录</button>
</view>
</view>
<template v-else>
<view v-if="!isVerified && !isVerifying" class="flex align-center justify-center" style="height: calc(100vh - 100rpx);">
<view class="flex flex-col align-center">
<text style="color: #747783;font-size: 28rpx;margin-bottom: 30rpx;">请先完成门店认证</text>
<button class="cu-btn" style="color: #FFFFFF; background-color: #4E63E0;" @click="toVerify">去认证</button>
</view>
</view>
<view v-else-if="isVerifying" class="flex align-center justify-center" style="height: calc(100vh - 100rpx);">
<view class="flex flex-col align-center">
<text style="color: #747783;font-size: 28rpx;margin-bottom: 30rpx;">您的门店正在认证中请耐心等待</text>
</view>
</view>
<template v-else>
<view v-if="tabCur == 0" class="my-container">
<template v-if="favoriteBeerList.length > 0">
<scroll-view
class="beer-scroll-view"
scroll-y
@scrolltolower="changeBeerPage"
:style="{ height: `calc(100vh - ${statusBarHeight}px - 88rpx)` }"
>
<view class="beer-list">
<view class="beer-item" v-for="(item, index) in favoriteBeerList" :key="index" @click="toBeer(item)">
<view class="beerCard flex align-center">
<image :src="item.cover" class="beer-cover" mode="aspectFill"></image>
<view class="flex-1 beer-info">
<view class="beer-name">{{item.beerName}}</view>
<view class="beer-style">{{ item.beerStyles}}</view>
<view class="brand-info flex align-center">
<image :src="item.brandLogo" class="brand-logo" mode="aspectFill"></image>
<text class="brand-name">{{ item.brandName}}</text>
</view>
<view class="rating-info flex align-center">
<text class="rating">
<text class="cuIcon-favorfill"></text>
{{ item.beerOverallRating || '5.0'}}
</text>
<text class="review-count">{{item.beerReviewsCount || '0'}} 条评论</text>
</view>
</view>
<view class="action-box">
<image src="/static/heart-remove.svg" class="cancel-icon" mode="aspectFit" @click.stop="cancelFavBeer(item)"></image>
</view>
</view>
</view>
</view>
<view class="cu-load" :class="favoriteBeerList.length == totalBeer ? 'over' :'more'"></view>
</scroll-view>
</template>
<template v-else>
<view class="empty-state">
<text class="cuIcon-like empty-icon"></text>
<text class="empty-text">暂无关注的酒款</text>
</view>
</template>
</view>
<view v-if="tabCur == 1" class="my-brandSide">
<template v-if="favoriteBreweryList.length > 0">
<scroll-view style="height: 100%;" scroll-y="true">
<view v-for="(item, index) in favoriteBreweryList" :key="index" class="brandSide-box" @tap="toBrand(item)">
<view class="flex align-center justify-start">
<image :src="item.brandLogo || '/static/default-brewery.png'" class="logo" mode="aspectFill" lazy-load></image>
<view class="info">
<view class="title">{{ item.brandName }}</view>
<view class="desc">全系列{{item.productCount || 'XXX'}}款产品在售</view>
</view>
</view>
<view class="action-box">
<image src="/static/heart-remove.svg" class="cancel-icon" mode="aspectFit" @click.stop="cancelFavBrewery(item)"></image>
</view>
</view>
</scroll-view>
</template>
<template v-else>
<view class="empty-state">
<text class="empty-text">暂无关注的品牌</text>
</view>
</template>
</view>
</template>
</template>
<loginPopup ref="loginRef" @loginSuccess="loginSuccess"></loginPopup>
</view>
</template>
<script>
import {
listMyFavoriteBeer,
listMyFavoriteBrewery
} from '@/api/user.js'
import {
favorBeer,
favorBrewery
} from '@/api/bar.js'
import loginPopup from '@/components/loginPopup.vue'
export default {
components: {
loginPopup
},
data() {
return {
isLogin: false,
isVerified: false,
isVerifying: false,
tabCur: 0,
scrollLeft: 0,
favoriteBeerList: [],
favoriteBreweryList: [],
totalBeer: 0,
totalBrewery: 0,
loading: false,
refreshing: false,
beerQuery: {
pageNum: 1,
pageSize: 10
},
breweryQuery: {
pageNum: 1,
pageSize: 10
}
};
},
onShow() {
this.checkLoginStatus()
},
onLoad() {
// 监听需要登录的事件
uni.$on('needLogin', () => {
this.toLogin()
})
},
onUnload() {
// 移除事件监听
uni.$off('needLogin')
},
methods: {
// 检查登录状态
checkLoginStatus() {
const token = uni.getStorageSync('token')
const userInfo = uni.getStorageSync('userInfo')
const barInfo = uni.getStorageSync('barInfo')
// 重置状态
this.isLogin = false
this.isVerified = false
this.isVerifying = false
this.favoriteBeerList = []
this.favoriteBreweryList = []
this.beerQuery.pageNum = 1
this.breweryQuery.pageNum = 1
if (!token || !userInfo) {
return
}
this.isLogin = true
// 检查认证状态
if (barInfo) {
if (barInfo.authState === 1) {
// 已认证
this.isVerified = true
this.isVerifying = false
} else if (barInfo.authState === 2) {
// 认证中
this.isVerified = false
this.isVerifying = true
} else {
// 未认证
this.isVerified = false
this.isVerifying = false
}
} else {
// 兼容旧版本使用userInfo中的isVerified
this.isVerified = userInfo?.isVerified === 1
this.isVerifying = false
}
// 如果已登录且已认证或正在认证中,获取关注列表
if (this.isVerified || this.isVerifying) {
this.getFavoriteBeerList()
this.getFavoriteBreweryList()
}
},
// 去登录
toLogin() {
this.$refs.loginRef.open()
},
// 去认证
toVerify() {
uni.navigateTo({
url: '/pages/index/registration'
})
},
// 登录成功
loginSuccess() {
// 重新检查登录状态
this.checkLoginStatus()
},
// 切换tab
tabSelect(e) {
this.tabCur = e.currentTarget.dataset.id
this.scrollLeft = (e.currentTarget.dataset.id - 1) * 60
},
// 获取收藏的酒款列表
getFavoriteBeerList() {
if(this.loading) return
this.loading = true
listMyFavoriteBeer(this.beerQuery).then(res => {
if (res.code === 200) {
this.totalBeer = res.total || 0
if (res.rows && res.rows.length > 0) {
if (this.beerQuery.pageNum === 1) {
this.favoriteBeerList = res.rows
} else {
this.favoriteBeerList = [...this.favoriteBeerList, ...res.rows]
}
} else if (this.beerQuery.pageNum === 1) {
this.favoriteBeerList = []
}
} else {
uni.showToast({
title: res.msg || '获取数据失败',
icon: 'none'
})
}
}).catch(err => {
console.error('获取酒款收藏列表失败:', err)
uni.showToast({
title: '获取数据失败,请重试',
icon: 'none'
})
}).finally(() => {
this.loading = false
this.refreshing = false
})
},
// 获取收藏的品牌列表
getFavoriteBreweryList() {
listMyFavoriteBrewery(this.breweryQuery).then(res => {
this.favoriteBreweryList = res.rows || []
})
},
// 取消收藏酒款
cancelFavBeer(item) {
uni.showModal({
title: '提示',
content: '确定取消收藏该酒款吗?',
success: (res) => {
if (res.confirm) {
favorBeer({
beerId: item.beerId,
status: 2
}).then(() => {
uni.showToast({
title: '取消成功',
icon: 'success'
})
// 重置数据
this.favoriteBeerList = []
this.beerQuery.pageNum = 1
this.getFavoriteBeerList()
})
}
}
})
},
// 取消收藏品牌
cancelFavBrewery(item) {
uni.showModal({
title: '提示',
content: '确定取消关注该品牌吗?',
success: (res) => {
if (res.confirm) {
favorBrewery({
breweryId: item.breweryId,
status: 2
}).then(() => {
uni.showToast({
title: '取消成功',
icon: 'success'
})
// 重置数据
this.favoriteBreweryList = []
this.breweryQuery.pageNum = 1
this.getFavoriteBreweryList()
})
}
}
})
},
// 跳转到酒款详情
toBeer(item) {
uni.navigateTo({
url: `/pages/index/review?beerId=${item.beerId}`
})
},
// 跳转到品牌详情
toBrand(item) {
uni.navigateTo({
url: `/pages/index/brandHome?breweryId=${item.breweryId}`
})
},
// 处理图片加载错误
handleImageError() {
console.log('图片加载失败');
},
// 切换酒款页码
changeBeerPage() {
if (this.loading) return;
if (this.favoriteBeerList.length >= this.totalBeer) return;
this.beerQuery.pageNum++;
this.getFavoriteBeerList();
}
}
}
</script>
<style lang="scss" scoped>
.page-content {
background: #F9F9F9;
height: 100vh;
.nav {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
padding: 0 32rpx;
background: #FFFFFF;
height: 88rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
.tab {
position: relative;
width: calc((100% - 56rpx) / 2);
margin: 0 14rpx;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
color: #1A1A1A;
font-weight: normal;
&.active {
color: #4E63E0;
font-weight: 600;
&::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 48rpx;
height: 4rpx;
background: #4E63E0;
border-radius: 2rpx;
}
}
}
}
.my-container {
padding: 0 36rpx;
margin-top: 88rpx;
height: calc(100vh - 88rpx);
position: relative;
.beer-scroll-view {
width: 100%;
box-sizing: border-box;
}
.beer-list {
padding: 28rpx 0;
.beer-item {
margin-bottom: 24rpx;
&:last-child {
margin-bottom: 0;
}
.beerCard {
border-radius: 12rpx;
background: #FFFFFF;
padding: 24rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
.beer-cover {
width: 144rpx;
height: 204rpx;
margin-right: 20rpx;
border-radius: 12rpx;
object-fit: cover;
}
.beer-info {
.beer-name {
font-size: 32rpx;
color: #1E2019;
font-weight: 500;
margin-bottom: 12rpx;
}
.beer-style {
font-size: 24rpx;
color: rgba(30, 32, 25, 0.8);
margin-bottom: 12rpx;
}
.brand-info {
margin-bottom: 12rpx;
.brand-logo {
width: 30rpx;
height: 30rpx;
margin-right: 12rpx;
border-radius: 50%;
}
.brand-name {
font-size: 28rpx;
color: #1E2019;
}
}
.rating-info {
.rating {
background: #F5F5F5;
padding: 8rpx 16rpx;
border-radius: 16rpx;
color: #5F5F63;
font-size: 24rpx;
margin-right: 16rpx;
.cuIcon-favorfill {
color: #FFBC11;
font-size: 30rpx;
margin-right: 4rpx;
}
}
.review-count {
color: #5F5F63;
font-size: 24rpx;
}
}
}
.action-box {
display: flex;
align-items: center;
.cancel-icon {
width: 40rpx;
height: 40rpx;
margin-right: 32rpx;
color: #030303;
filter: invert(0%) sepia(0%) saturate(0%) hue-rotate(324deg) brightness(0%) contrast(100%);
}
}
}
}
}
.empty-state {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60rpx;
.empty-icon {
font-size: 48rpx;
color: #CCCCCC;
margin-bottom: 12rpx;
}
.empty-text {
color: #747783;
font-size: 28rpx;
}
}
}
.my-brandSide {
padding: 28rpx 36rpx;
margin-top: 88rpx;
height: calc(100vh - 88rpx);
background: #F9F9F9;
.brandSide-box {
display: flex;
align-items: center;
justify-content: space-between;
padding: 32rpx 24rpx;
margin-bottom: 24rpx;
background: #FFFFFF;
border-radius: 12rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
.logo {
width: 108rpx;
height: 108rpx;
border-radius: 50%;
margin-right: 28rpx;
background-color: #f5f5f5;
flex-shrink: 0;
}
.info {
flex: 1;
min-width: 0;
.title {
font-size: 32rpx;
color: #19191B;
font-weight: 600;
margin-bottom: 12rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.desc {
font-size: 24rpx;
color: #9C9BA6;
}
}
.action-box {
.cancel-icon {
width: 40rpx;
height: 40rpx;
margin-right: 32rpx;
color: #030303;
filter: invert(0%) sepia(0%) saturate(0%) hue-rotate(324deg) brightness(0%) contrast(100%);
}
}
}
.empty-state {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60rpx;
.empty-text {
color: #747783;
font-size: 28rpx;
}
}
}
}
</style>