912 lines
24 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">
<view class="beer-container">
<view class="goods-box">
<image :src="beerInfo.cover" class="cover"></image>
<view class="flex-1">
<view class="flex justify-between align-center" style="margin-bottom: 28rpx;">
<view class="flex flex-1 justify-between align-center">
<text
style="font-size: 40rpx;color: #141415;font-weight: 600;margin-right: 8rpx;">{{ beerInfo.beerName || '--' }}</text>
<text v-if="!isFavor" class="cuIcon-like" style="font-size: 40rpx;color: #0B0E26"
@click="favorBeerFun(1)"></text>
<text v-else class="cuIcon-likefill" style="color: pink;font-size: 40rpx;" @click="favorBeerFun(2)"></text>
<!-- <image src="@/static/verify-mark.png" style="width: 48rpx;height: 48rpx;" @click="favorBeerFun(2)"> -->
</image>
</view>
<!-- <text class="cuIcon-like" style="color: #979797;font-size: 48rpx;"></text> -->
</view>
<view style="margin-bottom: 18rpx;font-size: 30rpx;color: #5F5F63;"> {{ beerInfo.beerStyles || '--' }}
</view>
<!-- <view style="margin-bottom: 18rpx;font-size: 30rpx;color: #5F5F63;">{{ item.launchDate }}</view> -->
<view class="flex align-center" style="gap:20rpx;margin-bottom: 18rpx;">
<uni-rate :readonly="true" :touchable="false" v-model="reviewScoreList.avgOverallRating || 0" />
{{ reviewScoreList.avgOverallRating || 0 }} / 5.0
</view>
<view v-if="beerInfo.breweryId" class="flex align-center justify-between" @click="toBrand">
<view class="flex align-center">
<image :src="beerInfo.brandLogo" style="width: 72rpx;height: 72rpx;margin-right: 12rpx;">
</image>
<text class="">{{ beerInfo.brandName || ''}}</text>
</view>
<image src="/static/arrow-right.png" style="width: 40rpx;height: 40rpx;"></image>
</view>
</view>
</view>
<view>
<view class="info-box flex justify-between margin-bottom">
<view class="info-item">
<text class="label">ABV</text>
<text class="item-text">{{beerInfo.beerAbv || '--'}}</text>
</view>
<view class="info-item">
<text class="label">IBU</text>
<text class="item-text">{{beerInfo.beerIbus || '--'}}</text>
</view>
<view class="info-item">
<text class="label">上市状态</text>
<text class="item-text">{{beerInfo.onSale == 1 ? '在售款' : '停售'}}</text>
</view>
</view>
<!-- <text class="desc word-all" v-html="beerInfo.desc"></text> -->
<rich-text class="desc word-all" :nodes="beerInfo.desc"></rich-text>
</view>
</view>
<!-- 大家评分 -->
<view class="score-box">
<view class="top">
<view class="left flex justify-between align-center">
<image src="/static/ranking.png" class="icon"></image>
<text v-if="currentTab == 1">我的评分</text>
<text v-if="currentTab == 2">大家评分</text>
</view>
<view class="right">
<view class="defTab" :class="{'active':currentTab == 1}" @click="currentTab = 1">
<image src="/static/user.png" class="icon"></image>
</view>
<view class="defTab" :class="{'active':currentTab == 2}" @click="currentTab = 2">
<image src="/static/users.png" class="icon"></image>
</view>
</view>
</view>
<view v-if="currentTab == 1">
<template v-if="myReviewInfo">
<view class="item-label flex justify-between align-center">
<text>颜色</text>
<text>{{myReviewInfo.colorRating}}</text>
</view>
<view class="slider-box">
<slider min="0" max="5" step="1" disabled :value="myReviewInfo.colorRating" activeColor="#FEE034"
backgroundColor="#f2f2f2" block-color="#FEE034" block-size="18" />
</view>
<view class="item-label flex justify-between align-center">
<text>香味</text>
<text>{{myReviewInfo.aromaRating}}</text>
</view>
<view class="slider-box">
<slider min="0" max="5" step="1" disabled :value="myReviewInfo.aromaRating" activeColor="#FEE034"
backgroundColor="#f2f2f2" block-color="#FEE034" block-size="18" />
</view>
<view class="item-label flex justify-between align-center">
<text>口味</text>
<text>{{myReviewInfo.tasteRating}}</text>
</view>
<view class="slider-box">
<slider min="0" max="5" step="1" disabled :value="myReviewInfo.tasteRating" activeColor="#FEE034"
backgroundColor="#f2f2f2" block-color="#FEE034" block-size="18" />
</view>
<view class="item-label flex justify-between align-center margin-top-sm">
<text>综合得分</text>
<text style="font-size: 30rpx;">
<text class="cuIcon-favorfill lg"
style="color:#FEE034;font-size: 40rpx;margin-right:10rpx"></text>
{{myReviewInfo.overallRating || 0}}</text>
</view>
</template>
<view v-else class="flex justify-center align-center" style="height: 80rpx;" @click="toPageBottom">
<text>你还没有评价,快来评价吧</text>
</view>
</view>
<view v-if="currentTab == 2">
<view class="item-label flex justify-between align-center">
<text>颜色</text>
<text>{{reviewScoreList.avgColorRating}}</text>
</view>
<view class="slider-box">
<slider min="0" max="5" step="1" disabled :value="reviewScoreList.avgColorRating"
activeColor="#FEE034" backgroundColor="#f2f2f2" block-color="#FEE034" block-size="18" />
</view>
<view class="item-label flex justify-between align-center">
<text>香味</text>
<text>{{reviewScoreList.avgAromaRating}}</text>
</view>
<view class="slider-box">
<slider min="0" max="5" step="1" disabled :value="reviewScoreList.avgAromaRating"
activeColor="#FEE034" backgroundColor="#f2f2f2" block-color="#FEE034" block-size="18" />
</view>
<view class="item-label flex justify-between align-center">
<text>口味</text>
<text>{{reviewScoreList.avgTasteRating}}</text>
</view>
<view class="slider-box">
<slider min="0" max="5" step="1" disabled :value="reviewScoreList.avgTasteRating"
activeColor="#FEE034" backgroundColor="#f2f2f2" block-color="#FEE034" block-size="18" />
</view>
<view class="item-label flex justify-between align-center margin-top-sm">
<text>综合得分</text>
<text style="font-size: 30rpx;">
<text class="cuIcon-favorfill lg"
style="color:#FEE034;font-size: 40rpx;margin-right:10rpx"></text>
{{reviewScoreList.avgOverallRating || 0}}</text>
</view>
</view>
</view>
<!-- 酒款评价 -->
<view class="review-box">
<view class="top">
<view class="left flex justify-between align-center">
<image src="/static/archive-tick.png" class="icon"></image>
<text>酒款评价</text>
</view>
<view v-if="reviewTotal > 0" class="right">
{{ reviewTotal }})条
</view>
</view>
<template v-if="reviewList.length > 0">
<view class="review-item" v-for="(item, index) in reviewList" :key="index">
<view class="flex margin-bottom-sm">
<!-- <image v-if="item.reviewImg" :src="item.reviewImg" class="avatar"></image> -->
<view class="flex flex-col">
<text class="beerName">{{ item.userName || '匿名用户' }}</text>
<text class="time">{{ item.createTime.slice(0,10) }}</text>
</view>
</view>
<view class="margin-bottom flex ">
<text class="word-all flex-1">
{{ item.reviewContent }}
</text>
<image v-if="item.reviewImg" :src="item.reviewImg"
style="width: 200rpx;height:200rpx;flex-shrink: 0;margin-left: 20rpx;"></image>
</view>
<view class="flex align-center justify-between">
<view class="flex align-center justify-start">
<image src="@/static/vector.png" class="icon"></image>
<text style="color:#5F5F63;margin-right: 40rpx;">{{ item.compositeScore }}</text>
<!-- <image src="@/static/message.png" class="icon"></image>
<text style="color:#979797">(100)</text> -->
</view>
<text v-if="!item.reviewLike" class="cuIcon-appreciate" style="font-size: 40rpx;margin-right: 40rpx;"
@click="handleLike(item)"></text>
<text v-else class="cuIcon-appreciatefill" style="font-size: 40rpx;margin-right: 40rpx;color: #FEE034;"
@click="handleLike(item)"
></text>
<!-- <view class="cu-btn line-grey round">删除</view> -->
</view>
</view>
<view v-if="reviewList.length < reviewTotal" style="color: #747783;font-size: 24rpx;text-align: center;" @click="reviewPageChange">查看更多评价</view>
<view v-else class="margin-top" style="color: #747783;font-size: 24rpx;text-align: center;">没有更多了</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 class="flex align-end flex-col bg-white padding margin-bottom">
<view class="lq-tip flex align-center">
<image src="@/static/warning-2.png" style="width: 30rpx;height:30rpx;margin-right: 12rpx;"></image>
首次写酒评还能领取啤酒币哦
</view>
<view class="flex justify-between align-center" style="width: 100%;padding-left: 52rpx;">
<!-- <view class="btn">
生成酒单
</view> -->
<view class="flex flex-col align-center" @click="createPic">
<image src="@/static/share.png" style="width: 48rpx;height: 48rpx;margin-bottom: 10rpx;"></image>
<text style="color: #030416;font-size: 20rpx;">酒款分享</text>
</view>
<view class="flex flex-col align-center" @click="toWinelist">
<image src="@/static/map.png" style="width: 48rpx;height: 48rpx;margin-bottom: 10rpx;"></image>
<text style="color: #030416;font-size: 20rpx;">生成酒单</text>
</view>
<view class="btn" style="background-color: #71F4B4;" @click="toWrite">
写酒评
</view>
</view>
</view>
<loginPopup ref="loginRef"></loginPopup>
<createPoster v-if="showShare" ref="createPosterRef" :url="tempUrl" @close="showShare=false"></createPoster>
<canvas type="2d" id="myCanvas" style="width: 360px;height: 570px;position: fixed;left:8888px"></canvas>
</view>
</template>
<script>
import {
getReviewInfo,
getReviewList,
getReviewScoreList,
getMyReviewInfo,
getBeerInfo,
favorBeer,
likeReview,
getBeerFavorStatus
} from '@/api/bar.js'
import loginPopup from '@/components/loginPopup.vue';
import createPoster from '@/components/createPoster.vue'
export default {
components: {
loginPopup,
createPoster
},
data() {
return {
tempUrl: '',
showShare: false,
beerId: '',
beerInfo: {}, // 酒款信息
reviewInfo: {},
reviewList: [], // 酒评列表
reviewScoreList: [], // 酒评评分
myReviewInfo: null,
currentTab: 2,
reviewTotal: 0, // 酒评总数
queryForm: {
beerId:'',
pageNum: 1,
pageSize: 5,
},
isFavor: false, // 是否收藏
};
},
onLoad({beerId}) {
this.beerId = beerId
this.queryForm.beerId = beerId
this.getBeerInfoFun()
// 只在登录状态下获取收藏状态
const token = uni.getStorageSync('token')
if (token) {
this.getBeerFavorStatusFun()
}
},
onShow() {
console.log('show')
this.reviewList = []
this.queryForm.pageNum = 1
this.getReviewListFun()
this.getReviewScoreListFun()
// 只在登录状态下获取我的酒评信息
const token = uni.getStorageSync('token')
if (token) {
this.getMyReviewInfoFun()
}
// 滚动到最顶
uni.pageScrollTo({
scrollTop: 0,
duration: 0,
})
},
methods: {
toPageBottom() {
uni.pageScrollTo({
scrollTop: 9999,
})
},
// 查询酒款收藏状态
getBeerFavorStatusFun() {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.open()
return
}
getBeerFavorStatus(this.beerId).then(res => {
if(res.data) {
this.isFavor = true
}else {
this.isFavor = false
}
})
},
// 获取酒款信息
getBeerInfoFun() {
getBeerInfo(this.beerId).then(res => {
this.beerInfo = res.data
})
},
// 获取酒评信息
getReviewInfoFun() {
getReviewInfo(this.beerId).then(res => {
this.reviewInfo = res.data
})
},
// 获取酒评列表
getReviewListFun() {
getReviewList(this.queryForm).then(res => {
if (res.rows) {
let arr = res.rows.map(it => {
it.compositeScore = this.getScore(it.aromaRating, it.tasteRating, it
.colorRating)
return it
})
if (arr.length > 0) {
arr.forEach(it => {
this.reviewList.push(it)
})
}
}
this.reviewTotal = res.total
})
},
// 酒评列表分页
reviewPageChange() {
this.queryForm.pageNum++
this.getReviewListFun()
},
// 获取酒评评分列表
getReviewScoreListFun() {
getReviewScoreList(this.beerId).then(res => {
this.reviewScoreList = res.data
})
},
// 获取我的酒评信息
getMyReviewInfoFun() {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.open()
return
}
getMyReviewInfo(this.beerId).then(res => {
this.myReviewInfo = res.data
})
},
// 写酒评
toWrite() {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.open()
return
}
// 检查认证状态
const barInfo = uni.getStorageSync('barInfo')
if (!barInfo) {
uni.showModal({
title: '提示',
content: '请先认证门店',
showCancel: true,
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/index/registration'
})
}
}
})
return
}
// 处理不同的认证状态
if (barInfo.authState === 0) {
uni.showModal({
title: '提示',
content: '请先认证门店',
showCancel: true,
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/index/registration'
})
}
}
})
return
} else if (barInfo.authState === 1) {
uni.showToast({
title: '您的门店正在认证中,请耐心等待',
icon: 'none'
})
return
}
uni.navigateTo({
url: '/pages/index/writeReview?beerId=' + this.beerId
})
},
// 计算综合评分
getScore(a, b, c) {
let score = 0
score = (a + b + c) / 3
return score.toFixed(0)
},
// 跳转 品牌方
toBrand() {
if (!this.beerInfo.breweryId) return
uni.navigateTo({
url: '/pages/index/brandHome?breweryId=' + this.beerInfo.breweryId
})
},
// 收藏酒款
favorBeerFun(status) {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.open()
return
}
// 检查认证状态
const barInfo = uni.getStorageSync('barInfo')
if (!barInfo) {
uni.showModal({
title: '提示',
content: '请先认证门店',
showCancel: true,
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/index/registration'
})
}
}
})
return
}
// 处理不同的认证状态
if (barInfo.authState === 0) {
uni.showModal({
title: '提示',
content: '请先认证门店',
showCancel: true,
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/index/registration'
})
}
}
})
return
} else if (barInfo.authState === 1) {
uni.showToast({
title: '您的门店正在认证中,请耐心等待',
icon: 'none'
})
return
}
let data = {
beerId: this.beerId,
status
}
favorBeer(data).then(res => {
if (status == 1) {
this.isFavor = true
uni.showToast({
title: '收藏成功',
icon: 'success'
})
} else {
this.isFavor = false
uni.showToast({
title: '取消收藏',
icon: 'none'
})
}
}).catch(err => {
if (err.code === 500 && err.msg.includes('门店未认证')) {
uni.showModal({
title: '提示',
content: '请先认证门店',
showCancel: true,
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/index/registration'
})
}
}
})
} else {
uni.showToast({
title: err.msg || '操作失败',
icon: 'none'
})
}
})
},
// 点赞
handleLike(item) {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.open()
return
}
let data = {
reviewId: item.id,
status: item.reviewLike ? 2 : 1
}
likeReview(data).then(res => {
if (data.status == 1) {
uni.showToast({
title: '点赞成功',
icon: 'none'
})
item.reviewLike = true
} else {
uni.showToast({
title: '取消点赞',
icon: 'none'
})
item.reviewLike = false
}
})
},
// 生成酒单
toWinelist() {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.open()
return
}
// 检查认证状态
const barInfo = uni.getStorageSync('barInfo')
if (!barInfo) {
uni.showModal({
title: '提示',
content: '请先认证门店',
showCancel: true,
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/index/registration'
})
}
}
})
return
}
// 处理不同的认证状态
if (barInfo.authState === 0) {
uni.showModal({
title: '提示',
content: '请先认证门店',
showCancel: true,
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/index/registration'
})
}
}
})
return
} else if (barInfo.authState === 1) {
uni.showToast({
title: '您的门店正在认证中,请耐心等待',
icon: 'none'
})
return
}
uni.navigateTo({
url: "/pagesActivity/winelist?beerId=" + this.beerId
})
},
// 分享
createPic() {
uni.showLoading({
title: '加载中'
})
let _this = this
// 获取的画布
uni.createSelectorQuery().select('#myCanvas').fields({
node: true,
size: true
}).exec((res) => {
const ctx = res[0].node.getContext('2d')
const canvas = res[0].node
const dpr = uni.getSystemInfoSync().pixelRatio
// const dpr = uni.getDeviceInfo().devicePixelRatio
// const dpr = uni.getSystemSetting().canvasToTempFilePath()
// 设置画布的宽高
canvas.width = res[0].width * dpr
canvas.height = res[0].height * dpr
ctx.scale(dpr, dpr)
let imageCover = canvas.createImage()
imageCover.src = this.beerInfo.cover
imageCover.onload = () => {
ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(imageCover, 0, 0, 360, 460)
// 绘制文字
ctx.font = `12px Arial`
ctx.fillStyle = '#0B0E26'
ctx.fillText(this.beerInfo.brandName, 20, 470)
ctx.font = `12px Arial`
ctx.fillStyle = '#0B0E26'
ctx.fillText(this.beerInfo.beerName, 20, 490)
ctx.font = `12px Arial`
ctx.fillStyle = '#5E5F60'
ctx.fillText(this.beerInfo.beerStyles, 20, 510)
// ctx.font = `${this.els.text3.fontSize}px Arial`
// ctx.fillStyle = this.els.text3.color
// ctx.fillText(this.els.text3.value, this.els.text3.x, this.els.text3.y)
// ctx.font = `${this.els.text4.fontSize}px Arial`
// ctx.fillStyle = this.els.text4.color
// ctx.fillText(this.els.text4.value, this.els.text4.x, this.els.text4.y)
// 保存图片
uni.canvasToTempFilePath({
canvas: canvas,
success: (res) => {
_this.tempUrl = res.tempFilePath
this.showShare = true
setTimeout(() => {
uni.hideLoading()
this.$refs.createPosterRef.open()
}, 1000)
},
fail: (err) => {
console.log(err)
uni.hideLoading()
},
})
}
})
},
}
}
</script>
<style lang="scss" scoped>
/deep/ slider {
margin: 0;
}
/deep/ .wx-slider-handle-wrapper {
margin: 0;
height: 36rpx !important;
}
.page {
min-height: 100vh;
background-color: #F6F6F6;
;
display: flex;
flex-direction: column;
justify-content: space-between;
// padding: 0rpx 28rpx 116rpx;
.lq-tip {
border-radius: 20rpx;
background: rgba(233, 233, 233, 0.38);
box-sizing: border-box;
border: 1px solid rgba(233, 233, 233, 0.3804);
padding: 10rpx;
font-size: 20rpx;
color: #5E5F60;
margin-bottom: 14rpx;
// width: 400rpx;
}
.btn {
border-radius: 30rpx;
box-sizing: border-box;
width: 306rpx;
height: 96rpx;
border-radius: 30rpx;
background-color: #FEE034;
font-size: 28rpx;
color: #1E2019;
display: flex;
align-items: center;
justify-content: center;
.icon {
width: 48rpx;
height: 48rpx;
margin-right: 22rpx;
}
}
.beer-container {
border-radius: 0rpx 0rpx 30rpx 30rpx;
background: #FFF;
box-sizing: border-box;
border: 1px solid #F2F2F2;
box-shadow: 0px 5.47px 43.78px 0px rgba(0, 0, 0, 0.05);
padding: 16rpx 40rpx;
.goods-box {
display: flex;
margin-bottom: 34rpx;
.cover {
width: 208rpx;
height: 300rpx;
border-radius: 12rpx;
margin-right: 14rpx;
}
}
.info-box {
.info-item {
border-radius: 36rpx;
background: rgba(255, 188, 17, 0.1);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 160rpx;
height: 164rpx;
.label {
font-family: Source Han Sans;
font-size: 30rpx;
font-weight: 500;
line-height: 44rpx;
color: #5F5F63;
margin-bottom: 9rpx;
}
.item-text {
font-family: Source Han Sans;
font-size: 30rpx;
font-weight: 500;
line-height: 44rpx;
color: #FFBC11;
}
}
}
.desc {
font-family: Source Han Sans;
font-size: 24rpx;
font-weight: 500;
line-height: 48rpx;
color: #A1A1A1;
}
}
.score-box {
border-radius: 30rpx;
background: #FFFFFF;
padding: 24rpx 28rpx 34rpx 34rpx;
margin-bottom: 32rpx;
.top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 22rpx;
.left {
font-family: Source Han Sans;
font-size: 36rpx;
font-weight: 500;
line-height: 44rpx;
color: #0B0E26;
.icon {
width: 48rpx;
height: 48rpx;
margin-right: 14rpx;
}
}
.right {
border-radius: 20rpx;
background: #F2F2F2;
display: flex;
justify-content: space-between;
.defTab {
width: 50%;
border-radius: 20rpx;
background: #F2F2F2;
display: flex;
justify-content: center;
align-items: center;
padding: 24rpx 36rpx;
.icon {
width: 48rpx;
height: 48rpx;
}
}
.active {
background-color: #71F4B4;
}
}
}
}
.review-box {
width: 100%;
// height: 200rpx;
padding: 0rpx 32rpx 30rpx;
border-radius: 30rpx;
background: #FFFFFF;
box-sizing: border-box;
border: 1px solid #F2F2F2;
.top {
display: flex;
justify-content: space-between;
align-items: center;
padding: 36rpx 10rpx 36rpx 0;
color: #0B0E26;
border-bottom: 1rpx solid rgba(242, 242, 242, 0.9);
.left {
font-family: Source Han Sans;
font-size: 36rpx;
font-weight: 500;
line-height: 44rpx;
.icon {
width: 48rpx;
height: 48rpx;
margin-right: 14rpx;
}
}
}
}
.review-item {
padding: 32rpx 0;
// margin-bottom: 32rpx;
border-bottom: 1rpx solid rgba(242, 242, 242, 0.9);
.avatar {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
margin-right: 36rpx;
}
.beerName {
font-size: 24rpx;
font-weight: bold;
color: #32343E;
margin-bottom: 8rpx;
}
.time {
font-size: 24rpx;
color: #9C9BA6;
}
.icon {
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
}
}
}
</style>