zdtap-uniapp-main/pagesMy/myAttention.vue

560 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 style="height: 100%;" enable-flex scroll-y @scrolltolower="changeBeerPage">
<view class="beer-grid">
<view class="beer-box" v-for="(item, index) in favoriteBeerList" :key="index" @click="toBeer(item)">
<view class="cover-box">
<image :src="item.cover" class="cover" mode="aspectFill"></image>
<view class="like">
<text class="cuIcon-likefill" style="color: #4E63E0"
@click.stop="cancelFavBeer(item)"></text>
</view>
</view>
<view class="info-box">
<view class="title">{{ item.beerName }}</view>
<view class="rating">
<text class="score">{{ item.beerOverallRating || '5' }}</text>
<text class="reviews">({{ item.beerReviewsCount || '0' }})</text>
</view>
</view>
</view>
</view>
<view class="cu-load" :class="favoriteBeerList.length == totalBeer ? 'over' :'more'"></view>
</scroll-view>
</template>
<template v-else>
<view class="flex align-center justify-center"
style="height: 140rpx;width: 100%;color: #747783;font-size: 24rpx;">暂无关注的酒款</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" @scrolltolower="changeBreweryPage">
<view class="brandSide-box" v-for="(item, index) in favoriteBreweryList" :key="index">
<view class="brand-info" @click="toBrand(item)">
<image :src="item.brandLogo" class="logo" mode="aspectFill" @error="handleImageError"></image>
<view class="brand-detail">
<view class="title">{{ item.brandName }}</view>
<view class="desc">{{ item.brandDesc }}</view>
</view>
</view>
<view class="cu-btn radius bg-gray" @click.stop="cancelFavBrewery(item)">取消关注</view>
</view>
<view class="cu-load" :class="favoriteBreweryList.length == totalBrewery ? 'over' :'more'"></view>
</scroll-view>
</template>
<template v-else>
<view class="flex align-center justify-center"
style="height: 140rpx;width: 100%;color: #747783;font-size: 24rpx;">暂无关注的品牌</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,
favoriteBeerList: [], // 收藏的酒款列表
favoriteBreweryList: [], // 收藏的酒厂列表
beerQuery: {
pageNum: 1,
pageSize: 10
},
breweryQuery: {
pageNum: 1,
pageSize: 10
},
totalBeer: 0,
totalBrewery: 0,
loading: false,
refreshing: false
};
},
onShow() {
this.checkLoginStatus()
},
onLoad() {
// 测试接口
console.log('开始测试接口...')
// 测试获取酒款收藏列表
listMyFavoriteBeer({
pageNum: 1,
pageSize: 10
}).then(res => {
console.log('酒款收藏列表测试成功:', res)
}).catch(err => {
console.error('获取酒款收藏列表失败:', err)
})
// 测试获取品牌收藏列表
listMyFavoriteBrewery({
pageNum: 1,
pageSize: 10
}).then(res => {
console.log('品牌收藏列表测试成功:', res)
}).catch(err => {
console.error('获取品牌收藏列表失败:', err)
})
// 测试取消收藏接口(需要有效的ID)
// favorBeer({
// beerId: 'xxx', // 需要替换为实际的beerId
// status: 2
// }).then(res => {
// console.log('取消酒款收藏测试成功:', res)
// }).catch(err => {
// console.error('取消酒款收藏失败:', err)
// })
// favorBrewery({
// breweryId: 'xxx', // 需要替换为实际的breweryId
// status: 2
// }).then(res => {
// console.log('取消品牌收藏测试成功:', res)
// }).catch(err => {
// console.error('取消品牌收藏失败:', err)
// })
// 原有的数据加载
this.getFavoriteBeerList()
this.getFavoriteBreweryList()
// 监听需要登录的事件
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()
},
tabSelect(e) {
this.tabCur = e.currentTarget.dataset.id
},
// 获取收藏的酒款列表
getFavoriteBeerList() {
if(this.loading) return
this.loading = true
listMyFavoriteBeer(this.beerQuery).then(res => {
this.totalBeer = res.total
if (res.rows && res.rows.length > 0) {
res.rows.forEach(it => {
this.favoriteBeerList.push(it)
})
}
}).finally(() => {
this.loading = false
this.refreshing = false
})
},
// 酒款翻页
changeBeerPage() {
if (this.favoriteBeerList.length < this.totalBeer) {
this.beerQuery.pageNum++
this.getFavoriteBeerList()
}
},
// 获取收藏的酒厂列表
getFavoriteBreweryList() {
if(this.loading) return
this.loading = true
listMyFavoriteBrewery(this.breweryQuery).then(res => {
console.log('品牌列表数据:', res.rows)
this.totalBrewery = res.total
if (res.rows && res.rows.length > 0) {
res.rows.forEach(it => {
// 直接使用原始数据,不做字段映射
this.favoriteBreweryList.push(it)
})
}
}).finally(() => {
this.loading = false
this.refreshing = false
})
},
// 品牌方翻页
changeBreweryPage() {
if (this.favoriteBreweryList.length < this.totalBrewery) {
this.breweryQuery.pageNum++
this.getFavoriteBreweryList()
}
},
// 跳转到酒款详情
toBeer(item) {
uni.navigateTo({
url: "/pages/index/review?beerId=" + item.beerId
})
},
// 跳转到品牌详情
toBrand(item) {
uni.navigateTo({
url: '/pages/index/brandHome?breweryId=' + item.breweryId
})
},
// 取消关注酒款
cancelFavBeer(item) {
let data = {
beerId: item.beerId,
status: 2
}
favorBeer(data).then(res => {
uni.showToast({
title: '取消收藏',
icon: 'none'
})
this.favoriteBeerList = []
this.beerQuery.pageNum = 1
this.getFavoriteBeerList()
})
},
// 取消关注酒厂
cancelFavBrewery(item) {
let data = {
breweryId: item.breweryId,
status: 2
}
favorBrewery(data).then(res => {
uni.showToast({
title: '取消收藏',
icon: 'none'
})
this.favoriteBreweryList = []
this.breweryQuery.pageNum = 1
this.getFavoriteBreweryList()
})
},
// 下拉刷新
onRefresh() {
this.refreshing = true
this.beerQuery.pageNum = 1
this.breweryQuery.pageNum = 1
this.favoriteBeerList = []
this.favoriteBreweryList = []
this.getFavoriteBeerList()
this.getFavoriteBreweryList()
},
// 处理图片加载错误
handleImageError(e) {
const target = e.target;
target.src = '/static/default-brand.png'; // 设置默认图片
}
}
}
</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;
transition: all 0.3s ease;
&.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: 28rpx 36rpx;
margin-top: 88rpx; // 为固定定位的导航栏留出空间
height: calc(100vh - 88rpx);
.beer-grid {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
margin: -14rpx; // 抵消子元素的margin
.beer-box {
width: calc((100% - 84rpx) / 3); // 三等分宽度(减去两个间距)
margin: 14rpx; // 统一的间距
background: #FFFFFF;
box-sizing: border-box;
display: flex;
flex-direction: column;
border-radius: 16rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
overflow: hidden;
.cover-box {
width: 100%;
padding-bottom: 144%; // 保持图片比例
position: relative;
overflow: hidden;
.cover {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.like {
position: absolute;
right: 16rpx;
bottom: 18rpx;
width: 48rpx;
height: 48rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(4rpx);
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
display: flex;
justify-content: center;
align-items: center;
}
}
.info-box {
padding: 12rpx;
.title {
font-size: 28rpx;
color: #19191B;
font-weight: 600;
margin-bottom: 8rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.rating {
display: flex;
align-items: center;
font-size: 24rpx;
.score {
color: #FFA033;
font-weight: 600;
margin-right: 4rpx;
}
.reviews {
color: #999999;
font-size: 20rpx;
}
}
}
}
}
}
.my-brandSide {
padding: 28rpx 36rpx;
margin-top: 88rpx; // 为固定定位的导航栏留出空间
height: calc(100vh - 88rpx);
.brandSide-box {
display: flex;
align-items: center;
justify-content: space-between;
padding: 32rpx 0;
border-bottom: 1rpx solid #F0F4F9;
.brand-info {
display: flex;
align-items: center;
flex: 1;
margin-right: 20rpx;
.logo {
width: 108rpx;
height: 108rpx;
border-radius: 50%;
margin-right: 28rpx;
background-color: #f5f5f5;
flex-shrink: 0;
}
.brand-detail {
flex: 1;
min-width: 0;
.title {
font-size: 28rpx;
color: #19191B;
margin-bottom: 12rpx;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.desc {
font-size: 24rpx;
color: #9C9BA6;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}
}
}
}
}
</style>