Files
MER-2.2_2601/mer_uniapp/pages/discover/components/discoverComment.vue
2026-03-08 20:07:52 +08:00

761 lines
19 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 v-if="noteDetail" class="main_content" :data-theme="theme" :class="!noteDetail.platReplySwitch?'bodyNo':''">
<popup-header v-if="!isShowCommentView && noteDetail.platReplySwitch && fromTo==='popupView'" title="评论" :num="noteDetail.replyNum" @close="close"></popup-header>
<!-- 评论列表 -->
<scroll-view class="bottom" id="myElements" scroll-y="true" @scrolltolower="onTouchmove" @scroll="followScroll"
v-if="noteDetail.platReplySwitch">
<view class="container">
<view v-if="list.length > 0" id="reply">
<view class="common_list" v-for="(item, index) in list" :key="index">
<view class="commen_one" @click.stop="goUserHomePage(item.uid)">
<image :src="item.avatar || urlDomain+'crmebimage/presets/morenT.png'" class="image">
</image>
</view>
<view class="info_count">
<view class="info">
<view class="message" @click.stop="toReply(item,index)">
<view v-if="item.nickname" class="name">{{item.nickname}}</view>
<view class="desc acea-row">
<view v-if="item.auditStatus==0" class="auditStatus">
<text class="line-heightOne">审核中</text>
</view>
<view style="width: 84%;">{{item.content}}</view>
</view>
<view class="acea-row row-middle" style="margin-top: 4rpx;">
<view class="time">{{item.createTime?$util.getDateDiff(item.createTime):''}}
</view>
<view @click.stop="toReply(item,index)" class="del mr-20">回复</view>
<text @click.stop="onDel(item, index)" v-if="item.uid == uid"
class="del">删除</text>
</view>
</view>
<view v-if="item.auditStatus!==0" class="like acea-row row-middle" @click.stop="starComment(item)">
<view class="iconfont mr-10" :class="item.isLike ? 'icon-icon_Like_2' : 'icon-ic_Like'">
</view>
{{item.countStart?item.countStart:0}}
</view>
</view>
<view v-if="item.replyList && item.replyList.length > 0" class="reply_count">
<view v-for="(itemn,indexn) in item.replyList" :key="indexn" class="reply_list">
<view class="item">
<view class="item_count" @click.stop="toReply(itemn,index)">
<image class="image" @click.stop="goUserHomePage(itemn.uid)"
:src="itemn.avatar || urlDomain+'crmebimage/presets/morenT.png'">
</image>
<view v-if="itemn.nickname" class="name_two">{{itemn.nickname}}
</view>
<view class="desc acea-row">
<view v-if="itemn.auditStatus==0" class="auditStatus mt10">
<text class="line-heightOne">审核中</text>
</view>
<view class="desc_two">
<text class="reply_user acea-row" v-if="Number(itemn.reviewUid) >0">回复<text class=ml-4>@{{itemn.reviewUserNickname}}</text> </text>{{itemn.content}}
</view>
</view>
<view class="acea-row row-middle" style="margin-top: 4rpx;">
<view class="time_two">
{{itemn.createTime?$util.getDateDiff(itemn.createTime):''}}
</view>
<view @click.stop="toReply(itemn,index)" class="del mr20">回复</view>
<text @click.stop="onDel(itemn, indexn, index)" v-if="itemn.uid == uid"
class="del">删除</text>
</view>
</view>
<view v-if="itemn.auditStatus!==0" class="like_two flex-y-center"
@click.stop="starComment(itemn)">
<view class="iconfont"
:class="itemn.isLike ? 'icon-icon_Like_2' : 'icon-ic_Like'"></view>
{{itemn.countStart ? itemn.countStart : 0}}
</view>
</view>
</view>
</view>
</view>
</view>
<view class="end"><text>到底了~~</text></view>
</view>
<view :hidden="!loading" class="acea-row row-center-wrapper loadingicon">
<text class="iconfont icon-jiazai loading"></text>
</view>
<view v-if="list.length == 0 && !loading" class="empty-box">
<image :src="urlDomain+'crmebimage/presets/noEvaluate.png'"></image>
<text>暂无评论快去抢沙发吧~</text>
</view>
</view>
</scroll-view>
<!-- 评论弹窗评论触发处 -->
<view v-if="fromTo==='popupView' && !isShowComment" @click="parentPinglun" class="release_bar bottoms">
<image class="image" :src="userInfo.avatar || urlDomain+'crmebimage/presets/morenT.png'"></image>
<view class="lang"
:style="'height: 32px; margin-left: 10px; background-color: #eee; border-radius: 50px; display: flex; flex-direction: row;'">
<text style="font-size: 13px; color: #999; margin-top: 7px; margin-left: 15px;">{{placeholder}}</text>
</view>
</view>
<!-- 真实评论弹窗 -->
<view v-show="isShowComment==true || (isShowCommentView && isClickBtn)" class="mask-popup"
:class="isShowComment==true || (isShowCommentView && isClickBtn)?'on':''">
<view class="release_bar" style="padding: 30rpx 24rpx;">
<image class="image mr-20" :src="userInfo.avatar || urlDomain+'crmebimage/presets/morenT.png'"></image>
<textarea :placeholder="placeholder" placeholder-style="color: #999999; font-size: 26rpx;"
v-model="content" :cursor-spacing="cursorSpacing" confirm-hold
:show-confirm-bar="false" class="input_count"
:focus="autoFocus" :adjust-position="adjustPosition" auto-height />
<button class="send ml-20" @click.stop="submitComment">发送</button>
</view>
</view>
<view class='mask' @touchmove.prevent catchtouchmove="true"
v-show="isShowComment || (isShowCommentView && isClickBtn &&!isShowComment)" @tap="closeComment"></view>
</view>
</template>
<script>
import {
mapGetters
} from "vuex";
import {
discoverNoteLike
} from '@/libs/follow.js';
import {
replyListApi,
noteReplyAddApi,
noteReplyLikeApi,
replyDeleteApi
} from '@/api/discover.js';
import {
toLogin
} from '@/libs/login.js';
import {
Debounce
} from '@/utils/validate.js'
import popupHeader from '@/components/popupHeader.vue'
let app = getApp();
export default {
name:'discoverComment',
computed: mapGetters(['isLogin', 'userInfo', 'uid']),
components: {
popupHeader
},
watch: {
noteId: {
handler: function(newV, oldV) {
if (newV) {
this.where.page = 1;
this.loading = false;
this.loaded = false;
this.list = [];
this.getList();
}
},
deep: true
},
noteDetails: {
handler: function(newV, oldV) {
if (newV) {
this.noteDetail = newV
}
},
deep: true
}
},
props: {
/* 哪里引用,页面中使用还是弹窗中使用评论 */
fromTo: {
type: String,
default: ''
},
/* 内容id */
noteId: {
type: Number,
default: 0
},
/* 逛逛详情 */
noteDetails: {
type: Object,
default: function() {
return {};
},
},
// 评论列表是否出现在详情视图内,出现就展示弹窗
isShowCommentView: {
type: Boolean,
default: false,
},
//是否点击了评论按钮
isClickBtn: {
type: Boolean,
default: false,
},
},
data() {
return {
urlDomain: this.$Cache.get("imgHost"),
cursorSpacing: 20, //键盘距离输入框的距离
adjustPosition: true, //默认
autoFocus: false,
noteDetail: this.noteDetails,
theme: app.globalData.theme,
content: '',
isShowComment: false, //真实评论弹窗显示隐藏
placeholder: "快来说点儿什么吧...",
loadTitle: '加载更多',
where: {
page: 1,
limit: 10,
noteId: ''
},
list: [],
loading: false,
replyId: 0,
focus: false,
index: 0,
isChild: false,
bottomVal: 0,
observer: null,
elementId: 'myElements',
}
},
mounted() {
this.getList();
},
onReady() {
},
onUnload() {
},
methods: {
//去个人主页
goUserHomePage(id){
this.$util.navigateTo(`/pages/discover/discover_user/index?id=${id}`);
},
//删除自己的评论
onDel(item, i, idx) {
uni.showModal({
title: '提示',
content: '确认删除评论吗?',
cancelColor: '#f55850',
success: res => {
if (res.confirm) {
this.onSub(item, i, idx);
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
},
onSub(item, i, idx) {
uni.showLoading({
title: '删除中...'
});
replyDeleteApi(item.id).then(res => {
if (item.type === 1) {
this.list.splice(i, 1);
} else {
this.list[idx].replyList.splice(i, 1)
}
uni.showToast({
title: '删除成功',
icon: 'none'
})
this.noteDetail.replyNum = res.data;
this.$emit('getReplyNum', this.noteDetail.replyNum)
uni.hideLoading();
}).catch(err => {
uni.hideLoading();
uni.showToast({
title: err,
icon: 'none'
})
});
},
/*点赞评论*/
starComment: Debounce(function(item) {
let that = this;
noteReplyLikeApi(item.id).then(res => {
this.$set(item, 'isLike', !item.isLike);
if (!item.isLike) {
item.countStart--;
item.countStart = item.countStart == 0 ? 0 : item.countStart
} else {
item.countStart++;
}
}).catch(err => {
uni.showToast({
title: err,
icon: 'none'
})
});
}),
// 模拟触底刷新
onTouchmove(e) {
if (this.loadend || this.loading) return;
this.getList();
},
/**
*
*/
followScroll() {
uni.$emit('scroll');
},
close() {
this.$emit('close');
},
//点赞
likeToggle: Debounce(function(item) {
if (this.isLogin) {
discoverNoteLike(item.id).then(() => {
this.$set(item, 'userIsLike', !item.userIsLike);
if (!item.userIsLike) {
item.likeNum--;
item.likeNum = item.likeNum == 0 ? 0 : item.likeNum
} else {
item.likeNum++;
}
});
} else {
toLogin();
}
}),
//回复
toReply(item, index) {
if (item.auditStatus === 0) return this.$util.Tips({
title: '审核中的评论不能进行回复'
});
this.placeholder = '回复:' + item.nickname
this.replyId = item.id
this.isChild = true
this.index = index
this.focus = true
this.content = ""
this.isShowComment = true
},
linechange(event) {
this.lineheight = event.detail.height
},
//真实评论弹窗 关闭
closeComment() {
this.autoFocus = false;
this.placeholder = "快来说点儿什么吧...";
this.content = ""
this.isChild = false
this.focus = false
this.bottomVal = 0
this.isShowComment = false;
//关闭评论蒙层
this.$emit('closeModelComment')
},
oninput() {
if (Number(this.noteDetail.replyStatus) > 1) {
return this.$util.Tips({
title: '该内容禁止评论'
});
} else {
this.isShowComment = true
}
},
parentPinglun() {
if (!this.isLogin) {
toLogin();
} else {
if (Number(this.noteDetail.replyStatus) > 1) {
return this.$util.Tips({
title: '该内容禁止评论'
});
} else {
this.autoFocus = false;
setTimeout(() => {
this.autoFocus = true;
this.isShowComment = true
}, 50)
}
}
},
//评论发送提交
submitComment: Debounce(function() {
if (!this.content) return;
noteReplyAddApi({
content: this.content,
noteId: this.noteId,
replyId: this.replyId
}).then(res => {
this.isShowComment = false
if (this.isChild) {
if (this.list[this.index]['replyList']) {
this.list[this.index]['replyList'].push(res.data)
} else {
this.list[this.index]['replyList'] = [res.data]
}
} else {
this.list.unshift(res.data)
}
this.noteDetail.replyNum = res.data.noteReplyNum
this.closeComment();
this.$util.Tips({
title: res.message
});
}).catch(err => {
this.isShowComment = false
uni.showToast({
title: err,
icon: 'none'
})
});
}),
//评论列表
getList() {
let that = this;
if (that.loading || that.loaded) return;
that.loading = true;
that.where.noteId = this.noteId;
replyListApi(that.where).then(res => {
that.loading = false;
that.all = res.data.all;
that.loaded = res.data.list.length < that.where.limit;
that.loadTitle = that.loadend ? '没有了' : '加载更多';
that.list.push.apply(that.list, res.data.list);
that.where.page = that.where.page + 1;
},
error => {
that.loading = false;
that.$util.Tips({
title: error.msg
})
}
);
},
}
}
</script>
<style lang="scss" scoped>
.author {
display: flex;
align-items: center;
position: relative;
.level_icon {
position: absolute;
width: 20rpx;
height: 20rpx;
margin: 4rpx 0 0 -4rpx;
border: none;
z-index: 1;
bottom: 2rpx;
left: 50rpx;
}
.picture,
uni-image {
width: 60rpx;
height: 60rpx;
border-radius: 100%;
}
.name {
margin-left: 20rpx;
color: #282828;
font-size: 32rpx;
font-weight: bold;
align-items: center;
}
}
.del {
font-size: 24rpx;
color: #999999;
display: inline-block;
}
.no-border {
position: static !important;
// border: none !important;
background-color: #fff;
z-index: 999 !important;
}
.release_box {
padding: 30rpx 0;
}
.lang {
width: 628rpx !important;
}
.bodyNo {
padding: 0 !important;
}
.main_content {
padding: 30rpx 24rpx;
}
.fixed {
position: fixed !important;
background-color: #fff;
}
.auditStatus {
font-size: 18rpx;
border-radius: 2px;
opacity: 1;
border: 1px solid #FE960F;
color: #FE960F;
height: 32rpx;
display: flex;
justify-content: center;
align-items: center;
margin-right: 8rpx;
padding: 0 4rpx;
}
.textarea {
bottom: constant(safe-area-inset-bottom); // 兼容 IOS<11.2
bottom: env(safe-area-inset-bottom); // 兼容 IOS>11.2
}
.bottom {
bottom: constant(safe-area-inset-bottom); // 兼容 IOS<11.2
bottom: env(safe-area-inset-bottom); // 兼容 IOS>11.2
}
.release_bar_detail {
height: calc(90rpx+ constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
height: calc(90rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
padding-bottom: constant(safe-area-inset-bottom); ///兼容 IOS<11.2/
padding-bottom: env(safe-area-inset-bottom); ///兼容 IOS>11.2/
background-color: #fff;
}
.release_bar {
background-color: #fff;
flex-shrink: 0;
width: 100%;
position: absolute; // input 所在盒子设置绝对定位
left: 0;
z-index: 999;
display: flex;
bottom: constant(safe-area-inset-bottom); ///兼容 IOS<11.2/
bottom: env(safe-area-inset-bottom); ///兼容 IOS>11.2/
align-items: center;
// justify-content: space-between;
padding: 15rpx 24rpx;
border-top: 1px solid #F5F5F5;
.avatar,
image,
uni-image {
width: 54rpx;
height: 54rpx;
border-radius: 100%;
}
.input_count {
width: 440rpx;
background: #F7F7F7;
border-radius: 40rpx;
height: 64rpx;
/* #ifdef H5 */
padding: 10rpx 30rpx;
/* #endif */
/* #ifndef H5 */
padding: 16rpx 30rpx;
/* #endif */
}
textarea {
width: 100%;
}
.send {
font-size: 26rpx;
color: #ffffff;
width: 120rpx;
height: 64rpx;
line-height: 64rpx;
text-align: center;
@include linear-gradient(theme);
border-radius: 30rpx;
text-align: center;
font-weight: 500;
}
.input_bar {
align-items: center;
color: #282828;
font-size: 26rpx;
.iconfont {
font-size: 40rpx;
margin-right: 6rpx;
}
.icon-ic_love_2 {
@include main_color(theme);
}
.item {
align-items: center;
&:first-child {
margin-right: 25rpx;
}
}
}
}
.container {
background-color: #fff;
position: relative;
height: 986rpx;
}
.end {
margin-top: 50rpx;
text-align: center;
text {
color: #999999;
font-size: 22rpx;
position: relative;
&::before,
&::after {
content: "";
display: inline-block;
width: 22rpx;
height: 1rpx;
background: #999999;
position: absolute;
top: 18rpx;
opacity: .5;
}
&::before {
left: -30rpx;
}
&::after {
right: -30rpx;
}
}
}
.common_list {
position: relative;
padding-left: 94rpx;
.commen_one {
position: absolute;
top: 0;
left: 0;
.image,
uni-image {
width: 74rpx;
height: 74rpx;
border-radius: 100%;
}
}
.info_count {
margin-bottom: 30rpx;
}
.info {
position: relative;
}
.name,
.name_two {
color: #999999;
font-size: 26rpx;
}
.desc,
.desc_two {
color: #282828;
font-size: 28rpx;
margin-top: 4rpx;
align-items: center;
}
.desc_two {
font-size: 28rpx;
width: 84%;
.reply_user {
font-size: 28rpx;
color: #4A8AC9;
display: inline-block;
margin: 0 6rpx 0 6rpx;
}
}
.time {
color: #bbb;
font-size: 24rpx;
margin-right: 20rpx;
}
.icon-cha2 {
font-size: 26rpx;
margin-top: 4rpx;
}
.time_two {
color: #bbb;
font-size: 24rpx;
margin-right: 20rpx;
}
.like,
.like_two {
color: #999999;
font-size: 26rpx;
text-align: center;
position: absolute;
top: 0;
right: 0;
width: 75rpx;
.icon-icon_Like_2 {
@include main_color(theme);
}
.iconfont{
margin-right: 10rpx;
}
}
.reply_list {
margin-top: 24rpx;
.item {
// padding-right: 140rpx;
position: relative;
}
.item_count {
position: relative;
padding-left: 56rpx;
.image,
un-image {
width: 36rpx;
height: 36rpx;
border-radius: 100%;
position: absolute;
top: 0;
left: 0;
}
}
}
}
</style>