2025-04-25 18:10:54 +08:00

774 lines
18 KiB
Vue
Executable File
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.

<style lang="scss" scoped>
.uni-popup-share {
background-color: #181717;
border-top-left-radius: 16rpx;
border-top-right-radius: 16rpx;
}
.uni-share-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: space-between;
height: 40px;
}
.uni-share-title-text {
font-size: 12px;
color: #ffffff;
font-weight: 500;
}
.uni-share-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
// flex-direction: row;
flex-direction: column;
// justify-content: center;
// padding-top: 10px;
}
.uni-share-content-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: wrap;
width: 360px;
}
.uni-share-content-item {
width: 90px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
padding: 10px 0;
align-items: center;
}
.uni-share-content-item:active {
background-color: #f5f5f5;
}
.uni-share-image {
width: 30px;
height: 30px;
}
.uni-share-text {
margin-top: 10px;
font-size: 14px;
color: #3b4144;
}
.uni-share-button-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
padding: 10px 15px;
}
.uni-share-button {
flex: 1;
border-radius: 50px;
color: #666;
font-size: 16px;
}
.uni-share-button::after {
border-radius: 50px;
}
.icon-close-left {
width: 20rpx;
height: 20rpx;
margin-left: 30rpx;
opacity: 0;
}
.icon-close-right {
width: 22rpx;
height: 22rpx;
margin-right: 30rpx;
}
.comment-wrapper {
// height: 40px;
padding: 10px 10px 10px 10px;
display: flex;
flex-direction: row;
justify-content: space-around;
}
.commentWrapperBlack {
background-color: #0e0d0d;
}
.commentWrapperWhite {
background-color: #ffffff;
}
.comment-box {
font-size: 15px;
height: 40px;
border-radius: 20px;
padding: 0 18px 0 18px;
}
.commentBoxBlack {
color: #ffffff;
background-color: #151515;
}
.commentBoxWhite {
color: #000000;
background-color: #f2f2f5;
}
.comment-box-placeholder {
font-size: 15px;
}
.icon-comment {
width: 30px;
height: 30px;
}
.all-comments {
height: 800rpx;
// padding: 16rpx 30rpx;
}
.img-face {
width: 80rpx;
height: 80rpx;
border-radius: 100rpx;
}
.like-or-not {
margin-top: 16px;
width: 50rpx;
height: 50rpx;
}
.comments-wrapper {
display: flex;
flex-direction: column;
}
.comments-wrapper-sub-up {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.comments-wrapper-sub-down {
display: flex;
flex-direction: row;
margin-top: 2px;
}
.vlogger-wrapper {
display: flex;
flex-direction: row;
}
.tag-writer {
display: flex;
flex-direction: column;
justify-content: center;
background-color: #f02a50;
border-radius: 3px;
width: 30px;
height: 16px;
margin-left: 2px;
}
.writer-words {
font-size: 26rpx;
color: #ffffff;
text-align: center;
}
.single-comment-box {
background-color: #181717;
}
.single-comment-box-touched {
background-color: #202020;
}
.active {
background-color: #202020;
}
</style>
<template>
<view class="uni-popup-share">
<view class="uni-share-title">
<image
src="/static/images/icon-close.png"
class="icon-close-left"
></image>
<text class="uni-share-title-text">{{ getGraceNumber(thisVlogTotalComentCounts) }}条评论</text>
<image
src="/static/images/icon-close.png"
class="icon-close-right"
@click="close"
></image>
</view>
<view class="uni-share-content">
<!-- <view class="uni-share-content-box"> -->
<view
class=""
style="height: 800rpx"
>
<scroll-view
class="all-comments"
:style="{ width: screenWidth + 'px' }"
scroll-y="true"
lower-threshold="150"
@scrolltolower="loadMore"
:scroll-top="scrollTop"
>
<view
v-for="(commentContent, index) in commentList"
:key="index"
:data-index="index"
:class="{ active: index == activeIndex }"
@touchstart="touchstartComment(index)"
@touchend="touchendComment()"
@longpress="deleteComment(commentContent.commentUserId, commentContent.commentId)"
>
<view
class="comments-wrapper"
style="margin-left: 16rpx; margin-top: 16rpx; margin-right: 16rpx"
>
<view class="comments-wrapper-sub-up">
<view class="vlogger-wrapper">
<image
:src="commentContent.commentUserFace"
class="img-face"
></image>
<view style="margin-left: 10px; width: 456rpx">
<view style="display: flex; flex-direction: row">
<text style="font-size: 30rpx; color: #878585; align-self: center">{{ commentContent.commentUserNickname }}</text>
<view
v-if="commentContent.vlogerId == thisVlogerId"
class="tag-writer"
style="align-self: center"
>
<text
class="writer-words"
style="align-self: center"
>
作者
</text>
</view>
<image
v-if="commentContent.replyedUserNickname != null && commentContent.replyedUserNickname != ''"
src="/static/images/icon-right-arrow3.png"
class=""
style="opacity: 0.8; width: 40rpx; height: 40rpx; margin-left: 16rpx; margin-right: 10rpx; align-self: center"
></image>
<text
v-if="commentContent.replyedUserNickname != null && commentContent.replyedUserNickname != ''"
style="font-size: 30rpx; color: #878585; align-self: center"
>
{{ commentContent.replyedUserNickname }}
</text>
</view>
<text style="font-size: 32rpx; color: #ffffff; margin-top: 2px">{{ commentContent.content }}</text>
</view>
</view>
<view style="display: flex; flex-direction: column; width: 26px">
<image
v-if="commentContent.isLike == 1"
src="/static/images/icon-comment-like.png"
class="like-or-not"
style="align-self: center"
@click="unlike(commentContent.commentUserId, commentContent.commentId, index)"
></image>
<image
v-if="commentContent.isLike == 0"
src="/static/images/icon-comment-unlike.png"
class="like-or-not"
style="align-self: center"
@click="like(commentContent.commentUserId, commentContent.commentId, index)"
></image>
<text style="font-size: 22rpx; color: #878585; align-self: center">{{ commentContent.likeCounts }}</text>
</view>
</view>
<view class="comments-wrapper-sub-down">
<image
src="/static/face/face-arrow-1.png"
class="img-face"
style="opacity: 0"
></image>
<text style="font-size: 30rpx; color: #878585; margin-left: 10px">{{ getGraceDateBeforeNow(commentContent.createTime) }}</text>
<text
style="font-size: 30rpx; color: #878585; margin-left: 20px"
@click="replyComment(commentContent.commentId, commentContent.commentUserNickname)"
>
回复
</text>
</view>
</view>
</view>
<!-- TODO: 判断总评论数和当前list中数量是否一致如果一致则显然如下 -->
<view style="display: flex; flex-direction: row; justify-content: center; margin-top: 50rpx; height: 100rpx">
<text style="color: #444446; font-size: 13px">{{ bottomTxt }}</text>
</view>
</scroll-view>
</view>
<!-- 评论输入框 -->
<view
class="comment-wrapper"
v-if="isLogin"
:class="{ commentWrapperBlack: commentWrapperBlack, commentWrapperWhite: commentWrapperWhite }"
>
<input
class="comment-box"
:class="{ commentBoxBlack: commentBoxBlack, commentBoxWhite: commentBoxWhite }"
placeholder-class="comment-box-placeholder"
:style="{ width: screenWidth - 70 + 'px' }"
:placeholder="placeholder"
cursor-spacing="10px"
v-model="currentComment"
confirm-type="done"
:focus="commentFocus"
@focus="typingComment"
@blur="noTypingComment"
/>
<!-- @confirm="doCommentPublish" -->
<view style="display: flex; flex-direction: column; justify-content: center">
<image
src="/static/images/icon-comment.png"
class="icon-comment"
@click="doCommentPublish()"
></image>
</view>
</view>
</view>
</view>
</template>
<script>
import storage from '@/utils/storage.js'; //缓存
import { vlogCommentCounts, vlogCommentUnLike, vlogCommentLike, vlogCommentDelete, vlogCommentList, vlogCommentCreate } from '@/api/vlog';
import { dateFormat, graceNumber, getDateBeforeNow } from '@/utils/tools.js';
import popup from '../uni-popup/popup.js';
export default {
name: 'UniPopupShare',
mixins: [popup],
emits: ['select'],
props: {
title: {
type: String,
default: '分享到'
},
beforeClose: {
type: Boolean,
default: false
},
thisVlogerId: {
type: String,
default: ''
},
thisVlogId: {
type: String,
default: ''
}
},
data() {
return {
isLogin: false,
commentWrapperBlack: true,
commentWrapperWhite: false,
commentBoxBlack: true,
commentBoxWhite: false,
// commentWrapperBlack: false,
// commentWrapperWhite: true,
// commentBoxBlack: false,
// commentBoxWhite: true,
screenWidth: uni.getSystemInfoSync().screenWidth,
currentComment: '',
scrollTop: 0,
old: {
scrollTop: 0
},
// commentTouched: false,
activeIndex: -1,
bottomTxt: '到底了哦~',
placeholder: '快发条评论吧~',
commentFocus: false,
thisFatherCommentId: '0', // 用于标识当前的回复是否有父id还是仅仅只是普通评论
thisVlogTotalComentCounts: 0,
loginUserId: '',
page: 0,
totalPage: 0,
commentCounts: 88,
commentList: []
};
},
onShow() {},
created() {
var me = this;
var myUserInfo = storage.getVlogUserInfo();
var userId = '';
if (myUserInfo != null) {
userId = myUserInfo.id;
this.isLogin = true;
} else {
this.isLogin = false;
}
me.loginUserId = userId;
this.freshCommentCounts();
this.doCommentPagingList(this.page + 1, true);
},
methods: {
//刷新评论
async freshCommentCounts() {
var me = this;
var vlogId = me.thisVlogId;
var result = await vlogCommentCounts(vlogId);
if (result.data.status == 200) {
me.thisVlogTotalComentCounts = result.data.data;
} else {
me.thisVlogTotalComentCounts = 0;
}
if (me.thisVlogTotalComentCounts == 0) {
me.bottomTxt = '抢一个沙发吧~';
} else {
me.bottomTxt = '到底了哦~';
}
},
async unlike(commentUserId, commentId, index) {
var me = this;
var myUserInfo = storage.getVlogUserInfo();
if (myUserInfo == null) {
uni.showTabBar({
animation: false
});
uni.navigateTo({
url: '/pages/passport/login',
animationType: 'slide-in-bottom'
});
return;
}
var me = this;
var result = await vlogCommentUnLike(me.loginUserId, commentId);
if (result.data.status == 200) {
me.reLikeCommentList(index, 0);
me.reCountsCommentList(index, -1);
} else {
uni.showToast({
title: result.data.msg,
icon: 'none',
duration: 3000
});
}
},
async like(commentUserId, commentId, index) {
var me = this;
var myUserInfo = storage.getVlogUserInfo();
if (myUserInfo == null) {
uni.showTabBar({
animation: false
});
uni.navigateTo({
url: '/pages/passport/login',
animationType: 'slide-in-bottom'
});
return;
}
var result = await vlogCommentLike(me.loginUserId, commentId);
if (result.data.status == 200) {
me.reLikeCommentList(index, 1);
me.reCountsCommentList(index, 1);
} else {
uni.showToast({
title: result.data.msg,
icon: 'none',
duration: 3000
});
}
},
reCountsCommentList(index, number) {
var me = this;
var commentList = me.commentList;
commentList[index].likeCounts = commentList[index].likeCounts + number;
commentList.splice(index, 1, commentList[index]);
me.commentList = commentList;
},
reLikeCommentList(index, isLike) {
var me = this;
var commentList = me.commentList;
commentList[index].isLike = isLike;
commentList.splice(index, 1, commentList[index]);
me.commentList = commentList;
},
deleteComment(commentUserId, commentId) {
var me = this;
var vlogId = me.thisVlogId;
// 判断如果当前登陆者userId和评论的留言者id不同不能删除
if (commentUserId != me.loginUserId) {
return;
}
uni.showModal({
title: '提示',
content: '确认删除评论吗?',
success: async (res) => {
if (res.confirm) {
var result = await vlogCommentDelete(vlogId, commentUserId, commentId);
if (result.data.status == 200) {
me.doCommentPagingList(1, true);
} else {
uni.showToast({
title: result.data.msg,
icon: 'none',
duration: 3000
});
}
me.freshCommentCounts();
}
}
});
},
loadMore() {
if (this.page == this.totalPage) {
return;
}
this.doCommentPagingList(this.page + 1, false);
},
// 分页查询评论列表
async doCommentPagingList(page, needClearList) {
var me = this;
me.page = page;
var vlogId = me.thisVlogId;
var result = await vlogCommentList(page, 10, vlogId, me.loginUserId);
if (result.data.status == 200) {
var commentList = result.data.data.rows;
console.log(commentList);
var totalPage = result.data.data.total;
if (needClearList) {
me.commentList = [];
}
me.commentList = me.commentList.concat(commentList);
me.totalPage = totalPage;
} else {
uni.showToast({
title: result.data.msg,
icon: 'none',
duration: 3000
});
}
},
// 获得焦点,改变底部文本框颜色
typingComment() {
this.commentWrapperBlack = false;
this.commentWrapperWhite = true;
this.commentBoxBlack = false;
this.commentBoxWhite = true;
// console.log(this.thisFatherCommentId);
},
// 失去焦点,改变底部文本框颜色
noTypingComment() {
this.commentWrapperBlack = true;
this.commentWrapperWhite = false;
this.commentBoxBlack = true;
this.commentBoxWhite = false;
this.thisFatherCommentId = '0'; // 恢复默认的回复fatherId为“0”
this.commentFocus = false;
this.placeholder = '爱评论的人都是天使~';
},
// 回复他人的评论
replyComment(commentId, commentUserNickname) {
var me = this;
var myUserInfo = storage.getVlogUserInfo();
if (myUserInfo == null) {
uni.showTabBar({
animation: false
});
uni.navigateTo({
url: '/pages/passport/login',
animationType: 'slide-in-bottom'
});
return;
}
this.thisFatherCommentId = commentId;
this.commentFocus = true;
this.placeholder = '回复 @' + commentUserNickname;
// this.typingComment();
},
// 发布留言
async doCommentPublish() {
console.log('发表评论');
var me = this;
var myUserInfo = storage.getVlogUserInfo();
if (myUserInfo == null) {
uni.showTabBar({
animation: false
});
uni.navigateTo({
url: '/pages/passport/login',
animationType: 'slide-in-bottom'
});
return;
}
if (me.currentComment == null || me.currentComment == '' || me.currentComment == undefined) {
uni.showToast({
title: '请填入您的评论~',
mask: true,
position: 'bottom'
});
return;
}
if (me.currentComment.length > 50) {
uni.showToast({
title: '评论字数限制50以内噢~',
mask: true,
position: 'bottom'
});
return;
}
var userId = myUserInfo.id;
var pendingCommentObject = {
vlogId: me.thisVlogId,
vlogerId: me.thisVlogerId,
fatherCommentId: me.thisFatherCommentId,
commentUserId: userId,
content: me.currentComment
};
var result = await vlogCommentCreate(pendingCommentObject);
console.log(result);
if (result.data.status == 200) {
var newCommentObject = result.data.data;
newCommentObject.commentId = newCommentObject.id;
newCommentObject.commentUserNickname = myUserInfo.nickname;
newCommentObject.commentUserFace = myUserInfo.face;
newCommentObject.isLike = 0;
newCommentObject.vlogerId = userId;
me.doCommentPagingList(1, true);
// 评论/回复完毕后回复thisFatherCommentId为“0”
me.thisFatherCommentId = '0';
// 把新评论添加到第一个位置,弱一致性,不需要从数据库里再去取
me.commentList.unshift(newCommentObject);
// 清空文本框
me.currentComment = '';
// 隐藏键盘
uni.hideKeyboard();
// 底部变色
me.noTypingComment();
// 把滚动list到第一个位置
me.scrollTop = me.scrollTop + 1;
me.$nextTick(() => {
me.scrollTop = 0; //赋值为0即代表返回顶部
});
} else {
uni.showToast({
title: result.data.msg,
icon: 'none',
duration: 3000
});
}
me.freshCommentCounts();
// uni.request({
// method: "POST",
// header: {
// headerUserId: userId,
// headerUserToken: app.getUserSessionToken()
// },
// url: serverUrl + "/comment/create",
// data: pendingCommentObject,
// success(result) {
// }
// });
},
// 把超过1000或10000的数字调整比如1.3k/6.8w
getGraceNumber(num) {
return graceNumber(num);
},
// 时间显示 刚刚/xx小时前/...
getGraceDateBeforeNow(dateTimeStr) {
// var date = dateFormat('YYYY-MM-DD HH:mm:ss', new Date(dateTimeStr));
return getDateBeforeNow(dateTimeStr);
},
/**
* 选择内容
*/
select(item, index) {
this.$emit('select', {
item,
index
});
this.close();
},
/**
* 关闭窗口
*/
close() {
if (this.beforeClose) return;
this.popup.close();
uni.showTabBar({
animation: true
});
},
touchstartComment(index) {
// this.commentTouched = true;
this.activeIndex = index;
},
touchendComment() {
// this.commentTouched = false;
this.activeIndex = -1;
}
}
};
</script>