2025-03-29 16:01:43 +08:00
|
|
|
|
<template>
|
|
|
|
|
<view class="page">
|
2025-04-07 00:15:19 +08:00
|
|
|
|
<!-- 商品信息卡片 -->
|
|
|
|
|
<view class="product-card">
|
|
|
|
|
<!-- 商品头部 -->
|
|
|
|
|
<view class="product-header">
|
|
|
|
|
<image class="product-image" :src="beerInfo.cover" mode="aspectFill"></image>
|
|
|
|
|
<view class="product-info">
|
|
|
|
|
<view class="title-row">
|
|
|
|
|
<text class="product-title">{{beerInfo.beerName || '--'}}</text>
|
|
|
|
|
<image v-if="!isFavor" class="like-btn" src="/static/heart-add.png" mode="aspectFit" @click="favorBeerFun(1)"></image>
|
|
|
|
|
<image v-else class="like-btn" src="/static/heart-tick.png" mode="aspectFit" @click="favorBeerFun(2)"></image>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
<text class="product-subtitle">{{beerInfo.beerStyles || '--'}}</text>
|
|
|
|
|
<view class="rating">
|
|
|
|
|
<text class="rating-score">{{reviewScoreList.avgOverallRating || 0}}/5.0</text>
|
|
|
|
|
<uni-rate :value="reviewScoreList.avgOverallRating || 0" :readonly="true" :touchable="false" size="18" />
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
<view v-if="beerInfo.breweryId" class="brand" @click="toBrand">
|
|
|
|
|
<image class="brand-logo" :src="beerInfo.brandLogo" mode="aspectFill"></image>
|
|
|
|
|
<text class="brand-name">{{beerInfo.brandName || ''}}</text>
|
|
|
|
|
<image class="arrow-icon" src="/static/arrow-right.png" mode="aspectFit"></image>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
|
|
|
|
|
<!-- 商品参数 -->
|
|
|
|
|
<view class="product-params">
|
|
|
|
|
<view class="param-item">
|
|
|
|
|
<text class="param-label">ABV</text>
|
|
|
|
|
<text class="param-value">≈{{beerInfo.beerAbv || '--'}}</text>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
<view class="param-item">
|
|
|
|
|
<text class="param-label">IBU</text>
|
|
|
|
|
<text class="param-value">{{beerInfo.beerIbus || '--'}}</text>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
<view class="param-item">
|
|
|
|
|
<text class="param-label">原麦汁</text>
|
|
|
|
|
<text class="param-value">{{beerInfo.onSale == 1 ? '在售款' : '停售'}}</text>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
|
|
|
|
|
<!-- 商品描述 -->
|
|
|
|
|
<view class="product-description">
|
|
|
|
|
<rich-text :nodes="beerInfo.desc"></rich-text>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<!-- 评分和评价 -->
|
|
|
|
|
<view class="rating-section">
|
|
|
|
|
<view class="section-title">评分和评价</view>
|
|
|
|
|
|
|
|
|
|
<!-- 评分总览 -->
|
|
|
|
|
<view class="rating-overview">
|
|
|
|
|
<text class="rating-score-large">{{currentTab === 2 ? (reviewScoreList.avgOverallRating || '-') : (myReviewInfo ? myReviewInfo.overallRating : '-')}}</text>
|
|
|
|
|
<view class="rating-right">
|
|
|
|
|
<uni-rate
|
|
|
|
|
:value="currentTab === 2 ? (reviewScoreList.avgOverallRating || 0) : (myReviewInfo ? myReviewInfo.overallRating : 0)"
|
|
|
|
|
:readonly="true"
|
|
|
|
|
:size="24"
|
|
|
|
|
:touchable="false"
|
|
|
|
|
color="#ECECEC"
|
|
|
|
|
active-color="#FEE034"
|
|
|
|
|
/>
|
|
|
|
|
<view class="rating-count" :class="{ highlight: currentTab === 1 && !myReviewInfo }">
|
|
|
|
|
<template v-if="currentTab === 2">
|
|
|
|
|
({{reviewTotal}}条)
|
|
|
|
|
</template>
|
|
|
|
|
<template v-else>
|
|
|
|
|
<template v-if="myReviewInfo">
|
|
|
|
|
{{myReviewInfo.createTime ? '评分于 ' + myReviewInfo.createTime.slice(0,10) : '我的评分'}}
|
|
|
|
|
</template>
|
|
|
|
|
<template v-else>
|
|
|
|
|
首次评分还可以领取品牌啤酒币哦
|
|
|
|
|
</template>
|
|
|
|
|
</template>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
<!-- 添加评分切换按钮 -->
|
|
|
|
|
<view class="rating-tabs">
|
|
|
|
|
<view class="tab-item" :class="{ active: currentTab === 2 }" @click="currentTab = 2">
|
|
|
|
|
<image class="tab-icon" src="/static/users.png" mode="aspectFit"></image>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
<view class="tab-item" :class="{ active: currentTab === 1 }" @click="currentTab = 1">
|
|
|
|
|
<image class="tab-icon" src="/static/user.png" mode="aspectFit"></image>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
</view>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
<!-- 评分条区域 -->
|
|
|
|
|
<view class="rating-bars">
|
|
|
|
|
<view class="rating-bar" v-for="(item, index) in [
|
|
|
|
|
{label: '外观', key: 'avgColorRating', weight: '10%',
|
|
|
|
|
value: currentTab === 2 ? reviewScoreList.avgColorRating : (myReviewInfo ? myReviewInfo.colorRating : 0)},
|
|
|
|
|
{label: '香气', key: 'avgAromaRating', weight: '30%',
|
|
|
|
|
value: currentTab === 2 ? reviewScoreList.avgAromaRating : (myReviewInfo ? myReviewInfo.aromaRating : 0)},
|
|
|
|
|
{label: '口感', key: 'avgTasteRating', weight: '60%',
|
|
|
|
|
value: currentTab === 2 ? reviewScoreList.avgTasteRating : (myReviewInfo ? myReviewInfo.tasteRating : 0)}
|
|
|
|
|
]" :key="index">
|
|
|
|
|
<view class="bar-header">
|
|
|
|
|
<text class="bar-label">{{item.label}} ({{item.weight}})</text>
|
|
|
|
|
<text class="bar-value">{{item.value ? item.value.toFixed(1) : '0.0'}}</text>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="bar">
|
|
|
|
|
<view class="bar-filled" :style="{width: item.value ? (item.value/5*100 + '%') : '0%'}"></view>
|
|
|
|
|
</view>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
|
|
|
|
|
<!-- 评价排序按钮 -->
|
|
|
|
|
<view class="review-sort">
|
|
|
|
|
<view class="sort-item" :class="{ active: sortType === 'latest' }" @click="sortType = 'latest'">
|
|
|
|
|
<text>最新</text>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
<view class="sort-item" :class="{ active: sortType === 'hot' }" @click="sortType = 'hot'">
|
|
|
|
|
<text>最热</text>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
|
|
|
|
|
<!-- 评论列表 -->
|
|
|
|
|
<view class="reviews" v-if="reviewList.length > 0">
|
|
|
|
|
<view class="review-item" v-for="(item, index) in reviewList.slice(0, 3)" :key="index">
|
|
|
|
|
<!-- 用户信息头部 -->
|
|
|
|
|
<view class="review-header">
|
|
|
|
|
<view class="user-info">
|
|
|
|
|
<image class="avatar" :src="item.userAvatar || '/static/default-avatar.png'" mode="aspectFill"></image>
|
|
|
|
|
<view class="user-meta">
|
|
|
|
|
<text class="user-name">{{item.userName || '匿名用户'}}</text>
|
|
|
|
|
<text class="review-time">{{item.createTime.slice(0,10)}}</text>
|
|
|
|
|
</view>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
<!-- 评论内容区域 -->
|
|
|
|
|
<view class="review-content">
|
|
|
|
|
<view class="content-left">
|
|
|
|
|
<!-- 评论文本 -->
|
|
|
|
|
<view class="review-text">
|
|
|
|
|
{{item.reviewContent}}
|
|
|
|
|
</view>
|
|
|
|
|
<!-- 评论图片区域 -->
|
|
|
|
|
<scroll-view v-if="item.reviewImg" class="image-scroll" scroll-x="true">
|
|
|
|
|
<view class="image-container">
|
|
|
|
|
<image
|
|
|
|
|
v-for="(img, imgIndex) in item.reviewImg.split(',')"
|
|
|
|
|
:key="imgIndex"
|
|
|
|
|
:src="img"
|
|
|
|
|
class="review-image"
|
|
|
|
|
mode="aspectFill"
|
|
|
|
|
@tap="previewImage(item.reviewImg.split(','), imgIndex)"
|
|
|
|
|
></image>
|
|
|
|
|
</view>
|
|
|
|
|
</scroll-view>
|
|
|
|
|
<!-- 评分和点赞 -->
|
|
|
|
|
<view class="review-footer">
|
|
|
|
|
<uni-rate
|
|
|
|
|
:value="item.compositeScore"
|
|
|
|
|
:readonly="true"
|
|
|
|
|
:size="16"
|
|
|
|
|
:touchable="false"
|
|
|
|
|
color="#ECECEC"
|
|
|
|
|
active-color="#FEE034"
|
|
|
|
|
/>
|
|
|
|
|
<text class="score-text">{{item.compositeScore}}分</text>
|
|
|
|
|
<view class="like-btn" :class="{ active: item.reviewLike }" @tap.stop="handleLike(item)">
|
|
|
|
|
<image class="like-icon" src="/static/like.png" mode="aspectFit"></image>
|
|
|
|
|
<text class="like-count">{{item.likeCount || 0}}</text>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
</view>
|
|
|
|
|
<view v-else class="no-review">巧了,还没有酒评呢,快拿下首评</view>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
<!-- 查看全部评价按钮 -->
|
|
|
|
|
<view v-if="reviewList.length > 0"
|
|
|
|
|
class="view-all-reviews"
|
|
|
|
|
:class="{ 'disabled': reviewList.length === 0 }"
|
|
|
|
|
@tap="toAllReviews">
|
|
|
|
|
查看全部评价
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<!-- 底部操作栏 -->
|
|
|
|
|
<view class="bottom-bar">
|
|
|
|
|
<view class="action-box">
|
|
|
|
|
<view class="action-item" @click="createPic">
|
|
|
|
|
<image class="action-icon" src="@/static/share.png" mode="aspectFit"></image>
|
|
|
|
|
<text class="action-text">酒款分享</text>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
<view class="action-item" @click="toWinelist">
|
|
|
|
|
<image class="action-icon" src="@/static/map.png" mode="aspectFit"></image>
|
|
|
|
|
<text class="action-text">生成酒单</text>
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
<view class="write-review" @click="toWrite">
|
|
|
|
|
{{ myReviewInfo ? '修改评分' : '为这款酒评分' }}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
|
|
|
|
|
<!-- 组件 -->
|
2025-03-29 16:01:43 +08:00
|
|
|
|
<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, // 是否收藏
|
2025-04-07 00:15:19 +08:00
|
|
|
|
sortType: 'latest',
|
2025-03-29 16:01:43 +08:00
|
|
|
|
};
|
|
|
|
|
},
|
2025-04-03 02:20:07 +08:00
|
|
|
|
onLoad({beerId}) {
|
2025-03-29 16:01:43 +08:00
|
|
|
|
this.beerId = beerId
|
|
|
|
|
this.queryForm.beerId = beerId
|
|
|
|
|
this.getBeerInfoFun()
|
2025-04-07 00:15:19 +08:00
|
|
|
|
this.getReviewListFun()
|
|
|
|
|
this.getReviewScoreListFun()
|
|
|
|
|
// 只在登录状态下获取收藏状态和我的评价信息
|
2025-04-03 02:20:07 +08:00
|
|
|
|
const token = uni.getStorageSync('token')
|
|
|
|
|
if (token) {
|
|
|
|
|
this.getBeerFavorStatusFun()
|
2025-04-07 00:15:19 +08:00
|
|
|
|
this.getMyReviewInfoFun()
|
2025-04-03 02:20:07 +08:00
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
},
|
|
|
|
|
onShow() {
|
|
|
|
|
console.log('show')
|
|
|
|
|
this.reviewList = []
|
|
|
|
|
this.queryForm.pageNum = 1
|
|
|
|
|
this.getReviewListFun()
|
|
|
|
|
this.getReviewScoreListFun()
|
2025-04-07 00:15:19 +08:00
|
|
|
|
// 只在登录状态下获取收藏状态和我的评价信息
|
2025-04-03 02:20:07 +08:00
|
|
|
|
const token = uni.getStorageSync('token')
|
|
|
|
|
if (token) {
|
2025-04-07 00:15:19 +08:00
|
|
|
|
this.getBeerFavorStatusFun()
|
2025-03-29 16:01:43 +08:00
|
|
|
|
this.getMyReviewInfoFun()
|
|
|
|
|
}
|
|
|
|
|
// 滚动到最顶
|
|
|
|
|
uni.pageScrollTo({
|
|
|
|
|
scrollTop: 0,
|
|
|
|
|
duration: 0,
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
toPageBottom() {
|
|
|
|
|
uni.pageScrollTo({
|
|
|
|
|
scrollTop: 9999,
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 查询酒款收藏状态
|
|
|
|
|
getBeerFavorStatusFun() {
|
2025-04-03 02:20:07 +08:00
|
|
|
|
const token = uni.getStorageSync('token')
|
|
|
|
|
if (!token) {
|
|
|
|
|
this.$refs.loginRef.open()
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
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) {
|
2025-04-07 00:15:19 +08:00
|
|
|
|
console.log('获取评论列表数据:', res.rows.length)
|
|
|
|
|
let arr = res.rows.map(it => ({
|
|
|
|
|
...it,
|
|
|
|
|
compositeScore: this.getScore(it.aromaRating, it.tasteRating, it.colorRating),
|
|
|
|
|
isExpanded: false,
|
|
|
|
|
needExpand: it.reviewContent && it.reviewContent.length > 50
|
|
|
|
|
}))
|
2025-03-29 16:01:43 +08:00
|
|
|
|
if (arr.length > 0) {
|
2025-04-07 00:15:19 +08:00
|
|
|
|
console.log('更新评论列表')
|
|
|
|
|
this.reviewList = [...this.reviewList, ...arr]
|
2025-03-29 16:01:43 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
this.reviewTotal = res.total
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 酒评列表分页
|
|
|
|
|
reviewPageChange() {
|
|
|
|
|
this.queryForm.pageNum++
|
|
|
|
|
this.getReviewListFun()
|
|
|
|
|
},
|
|
|
|
|
// 获取酒评评分列表
|
|
|
|
|
getReviewScoreListFun() {
|
|
|
|
|
getReviewScoreList(this.beerId).then(res => {
|
|
|
|
|
this.reviewScoreList = res.data
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 获取我的酒评信息
|
|
|
|
|
getMyReviewInfoFun() {
|
2025-04-03 02:20:07 +08:00
|
|
|
|
const token = uni.getStorageSync('token')
|
|
|
|
|
if (!token) {
|
|
|
|
|
this.$refs.loginRef.open()
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
getMyReviewInfo(this.beerId).then(res => {
|
|
|
|
|
this.myReviewInfo = res.data
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 写酒评
|
|
|
|
|
toWrite() {
|
2025-04-03 02:20:07 +08:00
|
|
|
|
const token = uni.getStorageSync('token')
|
|
|
|
|
if (!token) {
|
2025-03-29 16:01:43 +08:00
|
|
|
|
this.$refs.loginRef.open()
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-04-04 00:10:01 +08:00
|
|
|
|
|
|
|
|
|
// 检查认证状态
|
|
|
|
|
const barInfo = uni.getStorageSync('barInfo')
|
2025-04-05 14:07:39 +08:00
|
|
|
|
if (!barInfo) {
|
2025-04-04 00:10:01 +08:00
|
|
|
|
uni.showModal({
|
|
|
|
|
title: '提示',
|
|
|
|
|
content: '请先认证门店',
|
|
|
|
|
showCancel: true,
|
|
|
|
|
success: (res) => {
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
url: '/pages/index/registration'
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-05 14:07:39 +08:00
|
|
|
|
// 处理不同的认证状态
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-29 16:01:43 +08:00
|
|
|
|
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) {
|
2025-04-03 02:20:07 +08:00
|
|
|
|
const token = uni.getStorageSync('token')
|
|
|
|
|
if (!token) {
|
2025-03-29 16:01:43 +08:00
|
|
|
|
this.$refs.loginRef.open()
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-04-04 00:10:01 +08:00
|
|
|
|
|
|
|
|
|
// 检查认证状态
|
|
|
|
|
const barInfo = uni.getStorageSync('barInfo')
|
2025-04-06 14:55:47 +08:00
|
|
|
|
if (!barInfo || barInfo.authState === 0) {
|
2025-04-04 00:10:01 +08:00
|
|
|
|
uni.showModal({
|
|
|
|
|
title: '提示',
|
|
|
|
|
content: '请先认证门店',
|
|
|
|
|
showCancel: true,
|
|
|
|
|
success: (res) => {
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
url: '/pages/index/registration'
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-06 14:55:47 +08:00
|
|
|
|
if (barInfo.authState === 1) {
|
2025-04-05 14:07:39 +08:00
|
|
|
|
uni.showToast({
|
|
|
|
|
title: '您的门店正在认证中,请耐心等待',
|
|
|
|
|
icon: 'none'
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-29 16:01:43 +08:00
|
|
|
|
let data = {
|
|
|
|
|
beerId: this.beerId,
|
|
|
|
|
status
|
|
|
|
|
}
|
|
|
|
|
favorBeer(data).then(res => {
|
|
|
|
|
if (status == 1) {
|
2025-04-06 12:46:05 +08:00
|
|
|
|
this.isFavor = true
|
2025-03-29 16:01:43 +08:00
|
|
|
|
uni.showToast({
|
|
|
|
|
title: '收藏成功',
|
|
|
|
|
icon: 'success'
|
|
|
|
|
})
|
|
|
|
|
} else {
|
2025-04-06 12:46:05 +08:00
|
|
|
|
this.isFavor = false
|
2025-03-29 16:01:43 +08:00
|
|
|
|
uni.showToast({
|
|
|
|
|
title: '取消收藏',
|
|
|
|
|
icon: 'none'
|
|
|
|
|
})
|
|
|
|
|
}
|
2025-04-06 12:46:05 +08:00
|
|
|
|
}).catch(err => {
|
2025-04-06 14:55:47 +08:00
|
|
|
|
console.error('收藏操作失败:', err)
|
2025-04-06 12:46:05 +08:00
|
|
|
|
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'
|
|
|
|
|
})
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 点赞
|
|
|
|
|
handleLike(item) {
|
2025-04-03 02:20:07 +08:00
|
|
|
|
const token = uni.getStorageSync('token')
|
|
|
|
|
if (!token) {
|
2025-03-29 16:01:43 +08:00
|
|
|
|
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
|
2025-04-07 00:15:19 +08:00
|
|
|
|
item.likeCount = (item.likeCount || 0) + 1
|
2025-03-29 16:01:43 +08:00
|
|
|
|
} else {
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: '取消点赞',
|
|
|
|
|
icon: 'none'
|
|
|
|
|
})
|
|
|
|
|
item.reviewLike = false
|
2025-04-07 00:15:19 +08:00
|
|
|
|
item.likeCount = Math.max(0, (item.likeCount || 1) - 1)
|
2025-03-29 16:01:43 +08:00
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 生成酒单
|
|
|
|
|
toWinelist() {
|
2025-04-03 02:20:07 +08:00
|
|
|
|
const token = uni.getStorageSync('token')
|
|
|
|
|
if (!token) {
|
2025-03-29 16:01:43 +08:00
|
|
|
|
this.$refs.loginRef.open()
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-04-04 00:10:01 +08:00
|
|
|
|
|
|
|
|
|
// 检查认证状态
|
|
|
|
|
const barInfo = uni.getStorageSync('barInfo')
|
2025-04-05 14:07:39 +08:00
|
|
|
|
if (!barInfo) {
|
2025-04-04 00:10:01 +08:00
|
|
|
|
uni.showModal({
|
|
|
|
|
title: '提示',
|
|
|
|
|
content: '请先认证门店',
|
|
|
|
|
showCancel: true,
|
|
|
|
|
success: (res) => {
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
url: '/pages/index/registration'
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-05 14:07:39 +08:00
|
|
|
|
// 处理不同的认证状态
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-29 16:01:43 +08:00
|
|
|
|
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()
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
|
},
|
2025-04-07 00:15:19 +08:00
|
|
|
|
// 预览图片
|
|
|
|
|
previewImage(imgs, index) {
|
|
|
|
|
// 实现图片预览逻辑
|
|
|
|
|
console.log('Previewing image:', imgs[index])
|
|
|
|
|
},
|
|
|
|
|
// 跳转到全部评价页面
|
|
|
|
|
toAllReviews() {
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
url: '/pages/index/allReviews?beerId=' + this.beerId
|
|
|
|
|
})
|
|
|
|
|
},
|
2025-03-29 16:01:43 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
2025-04-07 00:15:19 +08:00
|
|
|
|
/* 页面容器 */
|
|
|
|
|
.page {
|
|
|
|
|
min-height: 100vh;
|
|
|
|
|
background-color: #F8F9FA;
|
|
|
|
|
padding-bottom: 220rpx;
|
|
|
|
|
font-family:-apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Roboto, "Segoe UI", "Microsoft YaHei", sans-serif;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 商品信息卡片 */
|
|
|
|
|
.product-card {
|
|
|
|
|
background: #fff;
|
|
|
|
|
margin: 24rpx;
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
border-radius: 24rpx;
|
|
|
|
|
box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.06);
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.product-header {
|
|
|
|
|
display: flex;
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
|
|
|
|
.product-image {
|
|
|
|
|
width: 242rpx;
|
|
|
|
|
height: 342rpx;
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
margin-right: 32rpx;
|
|
|
|
|
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.12);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.product-info {
|
|
|
|
|
flex: 1;
|
|
|
|
|
padding-top: 10rpx;
|
|
|
|
|
|
|
|
|
|
.title-row {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
margin-bottom: 16rpx;
|
|
|
|
|
|
|
|
|
|
.product-title {
|
|
|
|
|
flex: 1;
|
|
|
|
|
font-size: 40rpx;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #0B0E26;
|
|
|
|
|
margin-right: 20rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.like-btn {
|
|
|
|
|
margin-top: 4rpx;
|
|
|
|
|
width: 48rpx;
|
|
|
|
|
height: 48rpx;
|
|
|
|
|
padding: 4rpx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.product-subtitle {
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
color: #606060;
|
|
|
|
|
margin: 10rpx 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.rating {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 16rpx;
|
|
|
|
|
margin: 20rpx 0;
|
|
|
|
|
|
|
|
|
|
.rating-score {
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #333;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.brand {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
padding: 20rpx;
|
|
|
|
|
background: linear-gradient(to right, #f9f9f9, #ffffff);
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
margin-top: 20rpx;
|
|
|
|
|
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
|
|
|
|
|
|
|
|
|
.brand-logo {
|
|
|
|
|
width: 60rpx;
|
|
|
|
|
height: 60rpx;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
margin-right: 16rpx;
|
|
|
|
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.brand-name {
|
|
|
|
|
flex: 1;
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
color: #0B0E26;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.arrow-icon {
|
|
|
|
|
width: 32rpx;
|
|
|
|
|
height: 32rpx;
|
|
|
|
|
opacity: 0.6;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.product-params {
|
2025-03-29 16:01:43 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
2025-04-07 00:15:19 +08:00
|
|
|
|
padding: 0;
|
|
|
|
|
margin: 32rpx 0;
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.param-item {
|
|
|
|
|
width: 200rpx;
|
|
|
|
|
height: 180rpx;
|
|
|
|
|
background: linear-gradient(135deg, rgba(245, 197, 24, 0.1), rgba(245, 197, 24, 0.05));
|
|
|
|
|
border-radius: 16rpx;
|
2025-03-29 16:01:43 +08:00
|
|
|
|
display: flex;
|
2025-04-07 00:15:19 +08:00
|
|
|
|
flex-direction: column;
|
2025-03-29 16:01:43 +08:00
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
2025-04-07 00:15:19 +08:00
|
|
|
|
gap: 12rpx;
|
|
|
|
|
box-shadow: 0 4rpx 16rpx rgba(245, 197, 24, 0.1);
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.param-label {
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: #5F5F63;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.param-value {
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #FDCA40;
|
2025-03-29 16:01:43 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-07 00:15:19 +08:00
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.product-description {
|
|
|
|
|
padding: 0;
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
font-weight: normal;
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
color: #A1A1A1;
|
|
|
|
|
margin-bottom: 32rpx;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
/* 评分区域 */
|
|
|
|
|
.rating-section {
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
margin: 24rpx;
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
border-radius: 24rpx;
|
|
|
|
|
box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.06);
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.section-title {
|
|
|
|
|
font-size: 40rpx;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
line-height: 130%;
|
|
|
|
|
color: #030303;
|
|
|
|
|
margin-bottom: 36rpx;
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.rating-tabs {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
margin: 56rpx 0;
|
|
|
|
|
width: 100%;
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.tab-item {
|
|
|
|
|
width: 120rpx;
|
|
|
|
|
height: 80rpx;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
background: #F9F9F9;
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
|
|
&:first-child {
|
|
|
|
|
border-radius: 12rpx 0 0 12rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
&:last-child {
|
|
|
|
|
border-radius: 0 12rpx 12rpx 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tab-icon {
|
|
|
|
|
width: 60rpx;
|
|
|
|
|
height: 40rpx;
|
|
|
|
|
opacity: 0.6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
&.active {
|
|
|
|
|
background: #19367A;
|
|
|
|
|
box-shadow: 0 4rpx 12rpx rgba(25, 54, 122, 0.2);
|
|
|
|
|
|
|
|
|
|
.tab-icon {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
filter: brightness(0) invert(1);
|
2025-03-29 16:01:43 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-07 00:15:19 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.rating-overview {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
padding-left: 80rpx;
|
|
|
|
|
gap: 30rpx;
|
|
|
|
|
margin-bottom: 40rpx;
|
|
|
|
|
|
|
|
|
|
.rating-score-large {
|
|
|
|
|
font-size: 104rpx;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #030303;
|
|
|
|
|
line-height: 1;
|
|
|
|
|
min-width: 120rpx;
|
|
|
|
|
text-align: center;
|
|
|
|
|
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.rating-right {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
margin-left: 12rpx;
|
|
|
|
|
gap: 10rpx;
|
|
|
|
|
min-height: 80rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.rating-count {
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
margin-left: 12rpx;
|
|
|
|
|
color: #606060;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
min-height: 24rpx;
|
|
|
|
|
|
|
|
|
|
&.highlight {
|
|
|
|
|
color: #FDCA40;
|
2025-03-29 16:01:43 +08:00
|
|
|
|
font-weight: 500;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-07 00:15:19 +08:00
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.rating-bars {
|
|
|
|
|
margin: 32rpx 0;
|
|
|
|
|
|
|
|
|
|
.rating-bar {
|
|
|
|
|
margin-bottom: 16rpx;
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.bar-header {
|
2025-03-29 16:01:43 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
2025-04-07 00:15:19 +08:00
|
|
|
|
align-items: flex-start;
|
|
|
|
|
margin-bottom: 8rpx;
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.bar-label {
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
color: #606060;
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.bar-value {
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
color: #030303;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.bar {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 46rpx;
|
|
|
|
|
background: #F9F9F9;
|
|
|
|
|
border-radius: 23rpx;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
box-shadow: inset 0 2rpx 4rpx rgba(0, 0, 0, 0.05);
|
|
|
|
|
|
|
|
|
|
.bar-filled {
|
|
|
|
|
height: 100%;
|
|
|
|
|
background: linear-gradient(to right, #FDCA40, #FEE034);
|
|
|
|
|
border-radius: 23rpx;
|
|
|
|
|
box-shadow: 0 2rpx 8rpx rgba(253, 202, 64, 0.3);
|
2025-03-29 16:01:43 +08:00
|
|
|
|
}
|
2025-04-07 00:15:19 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.review-sort {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin: 32rpx 0;
|
|
|
|
|
gap: 16rpx;
|
|
|
|
|
padding-top: 24rpx;
|
|
|
|
|
|
|
|
|
|
.sort-item {
|
|
|
|
|
height: 64rpx;
|
|
|
|
|
padding: 0 24rpx;
|
|
|
|
|
background: #F9F9F9;
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
color: #606060;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
|
|
&.active {
|
|
|
|
|
background: #19367A;
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
box-shadow: 0 4rpx 12rpx rgba(25, 54, 122, 0.2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.reviews {
|
|
|
|
|
.review-item {
|
|
|
|
|
padding: 40rpx 32rpx;
|
|
|
|
|
margin: 24rpx 0;
|
|
|
|
|
background: #FFFFFF;
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
|
|
|
|
|
border: none;
|
|
|
|
|
|
|
|
|
|
&:last-child {
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.review-header {
|
|
|
|
|
margin-bottom: 32rpx;
|
|
|
|
|
|
|
|
|
|
.user-info {
|
2025-03-29 16:01:43 +08:00
|
|
|
|
display: flex;
|
2025-04-07 00:15:19 +08:00
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 24rpx;
|
|
|
|
|
|
|
|
|
|
.avatar {
|
|
|
|
|
width: 72rpx;
|
|
|
|
|
height: 72rpx;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
background: #f5f5f5;
|
|
|
|
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.user-meta {
|
|
|
|
|
flex: 1;
|
2025-03-29 16:01:43 +08:00
|
|
|
|
display: flex;
|
2025-04-07 00:15:19 +08:00
|
|
|
|
flex-direction: column;
|
|
|
|
|
gap: 12rpx;
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.user-name {
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
color: #333333;
|
|
|
|
|
font-weight: 500;
|
2025-03-29 16:01:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.review-time {
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
color: #999999;
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.review-content {
|
|
|
|
|
.content-left {
|
|
|
|
|
flex: 1;
|
|
|
|
|
min-width: 0;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
gap: 24rpx;
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.review-text {
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
line-height: 44rpx;
|
|
|
|
|
color: #333333;
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.image-scroll {
|
|
|
|
|
margin-top: 32rpx;
|
|
|
|
|
width: 100%;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
|
|
|
|
.image-container {
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
gap: 16rpx;
|
|
|
|
|
padding-right: 32rpx;
|
|
|
|
|
|
|
|
|
|
.review-image {
|
|
|
|
|
width: 220rpx;
|
|
|
|
|
height: 220rpx;
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.review-footer {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 24rpx;
|
|
|
|
|
margin-top: 24rpx;
|
|
|
|
|
padding-top: 24rpx;
|
|
|
|
|
border-top: 2rpx solid #f5f5f5;
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.score-text {
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
color: #FDCA40;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.like-btn {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 8rpx;
|
|
|
|
|
padding: 4rpx 12rpx;
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
background: rgba(25, 54, 122, 0.05);
|
|
|
|
|
|
|
|
|
|
.like-icon {
|
|
|
|
|
width: 32rpx;
|
|
|
|
|
height: 32rpx;
|
|
|
|
|
opacity: 0.6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.like-count {
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
color: #666666;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
&.active {
|
|
|
|
|
background: rgba(253, 202, 64, 0.1);
|
|
|
|
|
box-shadow: 0 2rpx 8rpx rgba(253, 202, 64, 0.2);
|
|
|
|
|
|
|
|
|
|
.like-icon {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.like-count {
|
|
|
|
|
color: #FDCA40;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-07 00:15:19 +08:00
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.view-all-reviews {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 88rpx;
|
|
|
|
|
margin: 40rpx 0;
|
|
|
|
|
border: 2rpx solid #19367A;
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
color: #19367A;
|
|
|
|
|
background: #FFFFFF;
|
|
|
|
|
box-shadow: 0 4rpx 12rpx rgba(25, 54, 122, 0.08);
|
|
|
|
|
|
|
|
|
|
&.disabled {
|
|
|
|
|
border-color: #CCCCCC;
|
|
|
|
|
color: #CCCCCC;
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.no-review {
|
|
|
|
|
text-align: center;
|
|
|
|
|
padding: 80rpx 0;
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
color: #606060;
|
|
|
|
|
background: #FFFFFF;
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
/* 底部操作栏 */
|
|
|
|
|
.bottom-bar {
|
|
|
|
|
position: fixed;
|
|
|
|
|
left: 0;
|
|
|
|
|
right: 0;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
background: #fff;
|
|
|
|
|
padding: 24rpx 32rpx env(safe-area-inset-bottom);
|
|
|
|
|
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
|
|
|
|
.action-box {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
padding: 12rpx 0;
|
|
|
|
|
|
|
|
|
|
.action-item {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 8rpx;
|
|
|
|
|
padding: 8rpx 16rpx;
|
|
|
|
|
|
|
|
|
|
.action-icon {
|
|
|
|
|
width: 48rpx;
|
|
|
|
|
height: 48rpx;
|
2025-03-29 16:01:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.action-text {
|
2025-03-29 16:01:43 +08:00
|
|
|
|
font-size: 24rpx;
|
2025-04-07 00:15:19 +08:00
|
|
|
|
color: #333;
|
|
|
|
|
margin-top: 4rpx;
|
2025-03-29 16:01:43 +08:00
|
|
|
|
}
|
2025-04-07 00:15:19 +08:00
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
|
2025-04-07 00:15:19 +08:00
|
|
|
|
.write-review {
|
|
|
|
|
width: 358rpx;
|
|
|
|
|
height: 96rpx;
|
|
|
|
|
background: linear-gradient(135deg, #19367A, #1E4B9E);
|
|
|
|
|
border-radius: 48rpx;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
color: #fff;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
margin: 0 16rpx;
|
|
|
|
|
box-shadow: 0 4rpx 16rpx rgba(25, 54, 122, 0.2);
|
2025-03-29 16:01:43 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-07 00:15:19 +08:00
|
|
|
|
}
|
2025-03-29 16:01:43 +08:00
|
|
|
|
</style>
|