shop_app/pages/groups/comment.vue

599 lines
15 KiB
Vue
Raw Permalink Normal View History

2025-05-08 09:16:37 +08:00
<template>
<!-- 团购评论 -->
<view class="whole">
<view class="tabBox">
<view class="Tit">
<view class="row" @click="changeTab(0)"><view class="tit" :class="tabIndex == 0 ? 'on' : ''">全部</view><text>({{total}})</text></view>
<view class="row" v-for="it in tabList" :key="it.id" @click="changeTab(it.id)">
<view class="tit" :class="tabIndex == it.id ? 'on' : ''">{{it.name}}</view><text>({{it.count}})</text>
</view>
</view>
<view class="filter">
<view class="icon" @click="showFilter = !showFilter">
<text class="iconfont icon-paixu"></text>
</view>
<view class="box" v-if="showFilter">
<view class="row" v-for="it in sortList" :key="it.id" @click="toFilter(it.id)" :class="sort == it.id ? 'on' : ''">{{it.name}}</view>
</view>
</view>
</view>
<scroll-view scroll-y="true" @scrolltolower="scorllBottom" style="height: calc(100vh - 90rpx);" lower-threshold="200">
<view class="oneBox">
<view class="cont">
<view class="top">
<view class="rateBox">
<view class="rate">{{goodCommentRate}}</view>
<text>好评率</text>
</view>
<view class="star">
<up-rate v-model="rateValue" :count="5" allowHalf readonly :size="25" activeColor="#ffd21e" inactiveColor="#eee" />
</view>
</view>
<view class="topBox">
<view class="row" v-for="item in tagsList" :key="item.id" :class="tagIndex === item.id ? 'active' : ''" @click="changeTag(item.id)">{{item.name}}&nbsp;<text>{{item.count}}</text></view>
</view>
</view>
</view>
<view class="listBox">
<view class="item" v-for="item in infoList" :key="item.id">
<view class="userInfo">
<image :src="item.user.avatar"></image>
<view class="box">
<view class="right">
<view class="name">{{item.user.nickname}}</view>
<span class="border" v-if="!from">已购{{item.report && item.report.total_trade_count}}</span>
</view>
<view class="time" v-if="!from">{{item.date.replace(/-/g, '/')}}发布于{{provTxt[item.order.province_id]}}</view>
</view>
</view>
<view class="starBox">
<view class="rate">
<view class="star" v-for="i in 5">
<up-icon v-if="i <= Math.ceil(item.stars)" name="star-fill" color="#FFD81E" size="18" />
<up-icon v-else name="star-fill" color="#ccc" :size="18" />
</view>
</view>
<view v-if="item.item" class="sku_name">{{item.item.goods_name}}
<template v-if="item.item.sku_name">{{item.item.sku_name}}</template>
</view>
<view class="tags" v-if="item.tags.length">
<text v-for="(it, i) in item.tags" :key="it.id"><template v-if="i != 0"> | </template>{{it.name}}</text>
</view>
</view>
<view class="comment"><text @longpress="copyComment(item.comment)">{{item.comment}}</text></view>
<view class="box_zong" v-if="item.material.length">
<view class="box_imgs" v-for="(it, index) in item.material" :key="index">
<image :src="it.url" v-if="it.type === 1" @click="hanleImgs(it, item.material)" mode="aspectFill"></image>
<template v-else>
<image :src="it.img_video" mode="aspectFill"></image>
<view class="play" @click="hanleImgs(it)"><up-icon name="play-right-fill" color="#fff" size="40" /></view>
</template>
</view>
</view>
<view class="replyBox" v-if="item.reply">
<view>店家回复</view>
<view class="text">{{item.reply}}</view>
</view>
<template v-if="item.add_comments && item.add_comments.length">
<view class="addBox" v-for="itm in item.add_comments" :key="itm.id">
<view class="tit">
<text>{{getDayDiff(itm.created_at.substr(0, 10), item.created_at.substr(0, 10))}}追评</text>
<text class="time">{{itm.created_at.substr(0, 16)}}</text>
</view>
<text class="comment" style="display: inline-block;margin-top: 10rpx;" @longpress="copyComment(itm.comment)">
{{itm.comment}}
</text>
<view class="box_zong" v-if="itm.material.length">
<view class="box_imgs" v-for="(it, index) in itm.material" :key="index">
<image :src="it.url" v-if="it.type === 1" @click="hanleImgs(it, itm.material)" mode="aspectFill"></image>
<template v-else>
<image :src="it.img_video" mode="aspectFill"></image>
<view class="play" @click="hanleImgs(it)"><up-icon name="play-right-fill" color="#fff" size="40" /></view>
</template>
</view>
</view>
<view class="replyBox itm" v-if="itm.reply">
<view>店家回复</view>
<view class="text">{{itm.reply}}</view>
</view>
</view>
</template>
</view>
<view class="bottom" v-if="page >= lastPage && infoList.length && !loading">- 到底啦 -</view>
<view class="bottom" v-if="loading"><up-loading-icon text="加载中..." textSize="14"></up-loading-icon></view>
</view>
<view v-if="!infoList.length && !loading">
<up-empty icon="https://ct-upimg.yx090.com/g.ii090/images/sprite/empty/comment.png" mode="comment" text="暂无评价喔" />
</view>
</scroll-view>
</view>
<video-dialog :url="videoUrl" :show="showVideo" @close="showVideo = false"></video-dialog>
<!-- 隐私协议弹窗 -->
<privacy-popup :show-dialog="showPrivacy" @close="showPrivacy = false" @agree="showPrivacy = false" @refuse="showPrivacy = false" />
</template>
<script>
import { ref, reactive, toRefs } from 'vue'
import { get } from '@/api/request.js'
import { Style } from '@/utils/list.js'
import privacyPopup from '@/components/privacyPopup/index.vue'
import { getDayDiff } from '@/components/common.js'
import videoDialog from '@/components/videoDialog/index.vue'
import { provTxt } from '@/components/scene.js'
export default {
components: {
privacyPopup, videoDialog
},
setup() {
const data = reactive({
tabIndex: 0,
id: '',
from: '',
infoList: [],
loading: false,
lastPage: 0,
page: 1,
showVideo: false,
videoUrl: '',
total: 0,
tagsList: [],
tagIndex: 0,
Color: uni.getStorageSync('theme_color'),
bgColor: Style[uni.getStorageSync('theme_index') * 1].bgColor,
showPrivacy: false,
is_show_sales: 'true',
goodCommentRate: '',
rateValue: 0,
showFilter: false,
sort: 0,
tabList: [
{id: 1, name: '图片/视频', count: 0},
{id: 2, name: '追评', count: 0},
{id: 3, name: '回头客', count: 0}
],
sortList: [
{id: 0, name: '默认排序'},
{id: 1, name: '最新评价'}
]
})
const hanleImgs = (it, imgs) => {
var img = []
imgs && imgs.forEach((res) => {
if (res.type == 1) {
img.push(res.url)
}
})
if (it.type === 1) {
uni.previewImage({
current: it.url,
urls: img
})
} else {
data.showVideo = true
data.videoUrl = it.url
}
}
// 触底加载下一页
function scorllBottom() {
if (data.page < data.lastPage) {
data.page++
getList()
}
}
const getList = (val = 0) => {
data.loading = true
get(`/api/v1/goods/comment/${data.id}`, {
page: data.page,
pageSize: 20,
type: 1,
stars_level: '',
has_material: '',
comment_tag_type: data.tabIndex || 0,
comment_tag_id: data.tagIndex || 0,
sortType: data.sort + 1
}).then((res) => {
data.infoList = data.infoList.concat(res.data)
data.goodCommentRate = res.goodCommentRate
data.rateValue = (res.goodCommentRate.split('%')[0] * 0.05).toFixed(2)
console.log(data.rateValue)
if(val == 1) {
data.total = res.meta.total
}
data.lastPage = data.is_show_sales == 'true' ? res.meta.last_page : 1
data.loading = false
}).catch(() => {
data.loading = false
})
}
// 复制评论
const copyComment = (text) => {
uni.setClipboardData({
data: String(text),
success: function () {
uni.showToast({
icon: 'none',
title: '评论已复制'
})
},
fail: function () {
uni.showToast({
icon: 'none',
title: '复制失败'
})
}
})
}
function changeTab(id) {
if(id == data.tabIndex) {
return
}
data.tagIndex = 0
data.tabIndex = id
data.page = 1
data.infoList = []
getList()
}
function changeTag(id) {
if(id == data.tagIndex) {
data.tagIndex = 0
} else {
data.tagIndex = id
}
data.tabIndex = 0
data.page = 1
data.infoList = []
getList()
}
function getTags() {
get(`/api/v1/orderComment/commentTags`, {type: 1, shop_group_goods_id: data.id}).then((res) => {
data.tabList[0].count = res.data[0].count
data.tabList[1].count = res.data[1].count
data.tabList[2].count = res.data[2].count
data.tagsList = res.data.slice(3)
})
}
function toFilter(id) {
data.sort = id
data.showFilter = false
data.page = 1
data.infoList = []
getList()
}
return {
getDayDiff,
provTxt,
...toRefs(data),
scorllBottom,
getList,
hanleImgs,
copyComment,
changeTab,
changeTag,
getTags,
toFilter
}
},
async onLoad(options) {
this.id = options.id
this.from = options.from || ''
this.is_show_sales = options.is_show_sales ? options.is_show_sales : 'true'
await this.getList(1)
this.getTags()
}
}
</script>
<style lang="scss" scoped>
.whole{
height: 100%;
box-sizing: border-box;
overflow: auto;
.tabBox{
background-color: #fff;
z-index: 2;
position: sticky;
top: 0;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24rpx 0;
box-sizing: border-box;
height: 90rpx;
.Tit{
display: flex;
align-items: center;
.row{
margin-right: 16rpx;
display: flex;
align-items: baseline;
&:last-child{
margin-right: 0;
}
.tit{
font-size: 30rpx;
color: #333;
font-weight: 600;
line-height: 1;
position: relative;
&.on::after{
position: absolute;
left: 0;
width: 56rpx;
height: 4px;
bottom: -5px;
content: '';
background: linear-gradient(to right, #fff -10%, v-bind('Color'));
}
}
text{
font-size: 22rpx;
color: #999;
}
}
}
.filter{
position: relative;
.icon{
display: flex;
align-items: center;
justify-content: flex-end;
height: 30px;
width: 30px;
.iconfont{
font-size: 18px;
}
}
.box{
position: absolute;
top: 60rpx;
right: -10rpx;
width: 200rpx;
text-align: center;
font-size: 28rpx;
padding: 14rpx 0;
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.2);
z-index: 2;
background-color: #fff;
border-radius: 8rpx;
&:before{
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
content: '';
border-top-width: 0;
border-bottom-color: #fff;
top: -6px;
right: 14rpx;
}
.row{
padding: 14rpx 0;
&.on{
color: v-bind('Color');
}
}
}
}
}
.oneBox{
padding: 24rpx;
.cont{
background-color: #fff;
padding: 24rpx 24rpx 8rpx;
border-radius: 10rpx;
}
.top{
display: flex;
align-items: center;
margin-bottom: 24rpx;
.rateBox{
font-size: 24rpx;
color: v-bind('Color');
.rate{
font-size: 42rpx;
font-weight: 600;
margin-bottom: 4px;
font-family: cursive;
}
}
.star{
border-left: 1px solid #f1f1f1;
padding-left: 24rpx;
margin-left: 24rpx;
}
}
}
.topBox{
display: flex;
align-items: center;
flex-wrap: wrap;
.row{
font-size: 24rpx;
color: #444;
padding: 6rpx 16rpx;
border-radius: 8rpx;
background-color: #F6F6F6;
margin: 0 16rpx 16rpx 0;
&.active{
background: v-bind('bgColor');
}
text{
color: #999;
}
}
}
.listBox{
padding: 0 24rpx 24rpx;
.item{
padding: 20rpx;
margin-bottom: 24rpx;
background-color: #fff;
.userInfo{
display: flex;
margin-bottom: 20rpx;
image{
width: 70rpx;
height: 70rpx;
border-radius: 50%;
margin-right: 15rpx;
}
.box{
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
.right{
font-size: 22rpx;
color: #98989f;
width: calc(100% - 150rpx);
.name{
font-size: 28rpx;
color: #333;
font-weight: bold;
margin-right: 10rpx;
display: inline-block;
}
.border{
height: 32rpx;
background: rgba(255, 255, 255, 0.39);
border: 1px solid v-bind('Color');
color: v-bind('Color');
padding: 0 10rpx;
border-radius: 5rpx;
font-size: 20rpx;
font-weight: normal;
}
}
.time{
font-size: 22rpx;
color: #999;
white-space: nowrap;
}
}
}
.starBox{
background-color: #F9F9F9;
padding: 16rpx 20rpx 20rpx;
border-radius: 8rpx;
.rate{
display: flex;
align-items: center;
.star{
margin-right: 3px;
}
}
.sku_name{
color: #999;
margin-top: 10rpx;
font-size: 24rpx;
width: 100%;
}
.tags{
margin-top: 16rpx;
color: #555;
font-size: 24rpx;
}
}
.comment{
display: inline-block;
font-size: 28rpx;
line-height: 48rpx;
margin-top: 20rpx;
}
.box_zong{
display: flex;
flex-wrap: wrap;
.box_imgs{
margin: 20rpx 20rpx 0 0;
position: relative;
width: 180rpx;
height: 180rpx;
&:nth-child(3n+3) {
margin-right: 0;
}
image{
width: 100%;
height: 100%;
vertical-align: bottom;
}
.play{
position: absolute;
left: 0;
top: 0;
background-color: rgba(0, 0, 0, 0.4);
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
z-index: 1;
}
}
}
.replyBox{
padding: 25rpx;
background: rgba(246, 246, 246, 0.6);
border-radius: 10rpx;
font-size: 28rpx;
margin-top: 24rpx;
&.itm{
border-radius: 0;
border-left: 3px solid #ddd;
}
.text{
margin-top: 20rpx;
color: #98989f;
}
}
.addBox{
background-color: #F7F7F7;
border-radius: 10rpx;
padding: 16rpx;
font-size: 28rpx;
margin-top: 24rpx;
.tit{
color: #f00;
display: flex;
align-items: center;
justify-content: space-between;
.time{
color: #98989f;
font-size: 24rpx;
}
}
}
}
.bottom {
text-align: center;
font-size: 24rpx;
color: #999999;
margin: auto;
line-height: 80rpx;
}
}
}
</style>