711 lines
18 KiB
Vue
711 lines
18 KiB
Vue
<template>
|
||
<view class="container">
|
||
<!-- 白色底部区域 -->
|
||
<view class="neighbor_body">
|
||
<!-- 正式页面内容 -->
|
||
<view class="body">
|
||
<view class="text-with-block">
|
||
<view class="left">
|
||
<text class="text">邻里互助详情</text>
|
||
<view class="slanted-block"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="interact_body">
|
||
<view class="body_item">
|
||
<view class="item_header">
|
||
<view class="left_section">
|
||
<image class="avatar" src="/static/imgs/index/nav.png"></image>
|
||
<view class="info">
|
||
<text class="name">樱桃小丸子</text>
|
||
<text class="date">03-24 07:30</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="body_content">
|
||
<h3>寻找拼车伙伴</h3>
|
||
<view class="content_font">
|
||
每天早晨7:30从社区出发前往政务中心上班,有同路的朋友可以拼车,分担车费。
|
||
</view>
|
||
<view class="content_img">
|
||
<image src="/static/imgs/index/swiper.png" mode="aspectFill"></image>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 评论输入框 -->
|
||
<view class="comment_input_area">
|
||
<input v-model="commentContent" class="comment_input" placeholder="写下你的评论..."
|
||
:focus="isInputFocus" @confirm="submitComment" />
|
||
<button class="submit_btn" @click="submitComment">发送</button>
|
||
</view>
|
||
|
||
<!-- 评论列表 -->
|
||
<view class="comment_list">
|
||
<view class="comment_title">全部评论 ({{ totalComments }})</view>
|
||
|
||
<!-- 主评论 -->
|
||
<view class="comment_item" v-for="(comment, index) in comments" :key="comment.id">
|
||
<image class="comment_avatar" :src="comment.avatar"></image>
|
||
<view class="comment_content">
|
||
<view class="comment_info">
|
||
<text class="comment_user">{{ comment.username }}</text>
|
||
<text class="comment_time">{{ comment.time }}</text>
|
||
</view>
|
||
<view class="comment_text">{{ comment.content }}</view>
|
||
<view class="comment_actions">
|
||
<text class="reply_btn" @click="showReplyInput(comment.id)">回复</text>
|
||
<text class="like_btn" @click="toggleCommentLike(comment)">
|
||
<image v-if="comment.isLiked" src="/static/icons/liked.png"
|
||
class="like_icon"></image>
|
||
<image v-else src="/static/icons/like.png" class="like_icon"></image>
|
||
{{ comment.likeCount || 0 }}
|
||
</text>
|
||
</view>
|
||
|
||
<!-- 回复输入框 -->
|
||
<view class="reply_input_area" v-if="activeReplyId === comment.id">
|
||
<input v-model="replyContent" class="reply_input" placeholder="写下你的回复..."
|
||
:focus="isReplyFocus" @confirm="submitReply(comment.id)" />
|
||
<button class="submit_btn" @click="submitReply(comment.id)">发送</button>
|
||
</view>
|
||
|
||
<!-- 子评论 -->
|
||
<view class="child_comments" v-if="comment.replies && comment.replies.length > 0">
|
||
<view class="child_comment_item" v-for="(reply, rIndex) in comment.replies"
|
||
:key="rIndex">
|
||
<image class="child_comment_avatar" :src="reply.avatar"></image>
|
||
<view class="child_comment_content">
|
||
<view class="comment_info">
|
||
<text class="comment_user">{{ reply.username }}</text>
|
||
<text class="comment_time">{{ reply.time }}</text>
|
||
</view>
|
||
<view class="comment_text">
|
||
<text class="reply_to"
|
||
v-if="reply.replyTo">@{{ reply.replyTo }}</text>
|
||
{{ reply.content }}
|
||
</view>
|
||
<view class="comment_actions">
|
||
<text class="reply_btn"
|
||
@click="showReplyInput(comment.id, reply.username)">回复</text>
|
||
<text class="like_btn" @click="toggleReplyLike(comment, reply)">
|
||
<image v-if="reply.isLiked" src="/static/icons/liked.png"
|
||
class="like_icon"></image>
|
||
<image v-else src="/static/icons/like.png" class="like_icon">
|
||
</image>
|
||
{{ reply.likeCount || 0 }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 查看更多回复 -->
|
||
<view class="view_more_replies"
|
||
v-if="comment.replies.length < comment.replyCount"
|
||
@click="loadMoreReplies(comment)">
|
||
查看全部{{ comment.replyCount }}条回复 ↓
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="comments.length === 0" class="no_comments">
|
||
暂无评论,快来发表第一条评论吧~
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 引入底部 -->
|
||
<Footer></Footer>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import Footer from '@/components/footer_common.vue';
|
||
export default {
|
||
components: {
|
||
Footer
|
||
},
|
||
data() {
|
||
return {
|
||
commentContent: '',
|
||
replyContent: '',
|
||
isInputFocus: false,
|
||
isReplyFocus: false,
|
||
activeReplyId: null,
|
||
replyToUser: '',
|
||
comments: [{
|
||
id: 1,
|
||
username: '邻居老王',
|
||
avatar: '/static/imgs/index/nav.png',
|
||
content: '我正好也去政务中心上班,可以一起拼车吗?',
|
||
time: '03-24 09:30',
|
||
isLiked: false,
|
||
likeCount: 3,
|
||
replyCount: 2,
|
||
replies: [{
|
||
id: 11,
|
||
username: '樱桃小丸子',
|
||
avatar: '/static/imgs/index/nav.png',
|
||
content: '当然可以啊,你住在哪栋楼?',
|
||
time: '03-24 09:45',
|
||
isLiked: true,
|
||
likeCount: 1,
|
||
replyTo: '邻居老王'
|
||
},
|
||
{
|
||
id: 12,
|
||
username: '邻居老王',
|
||
avatar: '/static/imgs/index/nav.png',
|
||
content: '我住3栋,你呢?',
|
||
time: '03-24 09:50',
|
||
isLiked: false,
|
||
likeCount: 0,
|
||
replyTo: '樱桃小丸子'
|
||
}
|
||
]
|
||
},
|
||
{
|
||
id: 2,
|
||
username: '社区小李',
|
||
avatar: '/static/imgs/index/nav.png',
|
||
content: '我每周一三五去那边,可以固定拼车',
|
||
time: '03-24 10:15',
|
||
isLiked: false,
|
||
likeCount: 1,
|
||
replyCount: 1,
|
||
replies: [{
|
||
id: 21,
|
||
username: '樱桃小丸子',
|
||
avatar: '/static/imgs/index/nav.png',
|
||
content: '好的,那周一见!',
|
||
time: '03-24 10:30',
|
||
isLiked: false,
|
||
likeCount: 0,
|
||
replyTo: '社区小李'
|
||
}]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
computed: {
|
||
totalComments() {
|
||
let count = this.comments.length;
|
||
this.comments.forEach(comment => {
|
||
count += comment.replies.length;
|
||
});
|
||
return count;
|
||
}
|
||
},
|
||
methods: {
|
||
submitComment() {
|
||
if (this.commentContent.trim() === '') return;
|
||
|
||
const newComment = {
|
||
id: Date.now(),
|
||
username: '当前用户',
|
||
avatar: '/static/imgs/index/nav.png',
|
||
content: this.commentContent,
|
||
time: this.formatDate(new Date()),
|
||
isLiked: false,
|
||
likeCount: 0,
|
||
replyCount: 0,
|
||
replies: []
|
||
};
|
||
|
||
this.comments.unshift(newComment);
|
||
this.commentContent = '';
|
||
this.isInputFocus = false;
|
||
},
|
||
showReplyInput(commentId, replyTo = '') {
|
||
this.activeReplyId = commentId;
|
||
this.replyToUser = replyTo;
|
||
this.replyContent = '';
|
||
this.$nextTick(() => {
|
||
this.isReplyFocus = true;
|
||
});
|
||
},
|
||
submitReply(commentId) {
|
||
if (this.replyContent.trim() === '') return;
|
||
|
||
const parentComment = this.comments.find(c => c.id === commentId);
|
||
if (!parentComment) return;
|
||
|
||
const newReply = {
|
||
id: Date.now(),
|
||
username: '当前用户',
|
||
avatar: '/static/imgs/index/nav.png',
|
||
content: this.replyContent,
|
||
time: this.formatDate(new Date()),
|
||
isLiked: false,
|
||
likeCount: 0,
|
||
replyTo: this.replyToUser || parentComment.username
|
||
};
|
||
|
||
parentComment.replies.push(newReply);
|
||
parentComment.replyCount = parentComment.replies.length;
|
||
this.replyContent = '';
|
||
this.activeReplyId = null;
|
||
this.isReplyFocus = false;
|
||
this.replyToUser = '';
|
||
},
|
||
toggleCommentLike(comment) {
|
||
comment.isLiked = !comment.isLiked;
|
||
comment.likeCount += comment.isLiked ? 1 : -1;
|
||
},
|
||
toggleReplyLike(comment, reply) {
|
||
reply.isLiked = !reply.isLiked;
|
||
reply.likeCount += reply.isLiked ? 1 : -1;
|
||
},
|
||
loadMoreReplies(comment) {
|
||
// 模拟加载更多回复
|
||
const newReplies = [{
|
||
id: Date.now() + 1,
|
||
username: '热心邻居',
|
||
avatar: '/static/imgs/index/nav.png',
|
||
content: '我也想去政务中心,可以一起吗?',
|
||
time: '03-25 08:00',
|
||
isLiked: false,
|
||
likeCount: 0,
|
||
replyTo: comment.username
|
||
},
|
||
{
|
||
id: Date.now() + 2,
|
||
username: '社区志愿者',
|
||
avatar: '/static/imgs/index/nav.png',
|
||
content: '拼车注意安全哦!',
|
||
time: '03-25 08:30',
|
||
isLiked: false,
|
||
likeCount: 0,
|
||
replyTo: comment.username
|
||
}
|
||
];
|
||
|
||
comment.replies = [...comment.replies, ...newReplies];
|
||
comment.replyCount = comment.replies.length;
|
||
},
|
||
formatDate(date) {
|
||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||
const day = date.getDate().toString().padStart(2, '0');
|
||
const hours = date.getHours().toString().padStart(2, '0');
|
||
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||
return `${month}-${day} ${hours}:${minutes}`;
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
background: #f8faff;
|
||
min-height: 100vh;
|
||
padding-bottom: 120rpx;
|
||
|
||
.neighbor_head {
|
||
width: 100%;
|
||
height: 360rpx;
|
||
opacity: 1;
|
||
background: linear-gradient(270deg, rgba(146, 161, 252, 1) 0%, rgba(181, 229, 255, 1) 100%);
|
||
position: relative;
|
||
}
|
||
|
||
.neighbor_body {
|
||
width: 100%;
|
||
background: #fff;
|
||
min-height: calc(100vh - 360rpx);
|
||
border-top-left-radius: 40rpx;
|
||
border-top-right-radius: 40rpx;
|
||
position: relative;
|
||
top: -40rpx;
|
||
z-index: 9;
|
||
padding-bottom: 120rpx;
|
||
box-shadow: 0 -10rpx 20rpx rgba(0, 0, 0, 0.05);
|
||
|
||
.body {
|
||
width: 90%;
|
||
margin: 0 auto;
|
||
padding-top: 40rpx;
|
||
|
||
.text-with-block {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
padding: 20rpx 0;
|
||
height: 60rpx;
|
||
/* 增加高度 */
|
||
margin-bottom: 40rpx;
|
||
position: relative;
|
||
|
||
.left {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.text {
|
||
font-size: 38rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
position: relative;
|
||
z-index: 2;
|
||
padding-left: 20rpx;
|
||
background: linear-gradient(to right, #4a8cff, #80b3ff);
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
color: transparent;
|
||
text-shadow: 0 2rpx 4rpx rgba(74, 140, 255, 0.2);
|
||
}
|
||
|
||
.slanted-block {
|
||
position: absolute;
|
||
left: 0;
|
||
bottom: 0;
|
||
transform: skewX(-15deg);
|
||
width: 240rpx;
|
||
height: 16rpx;
|
||
/* 调整为更细的线条 */
|
||
background: linear-gradient(90deg, rgba(74, 140, 255, 0.6), rgba(128, 179, 255, 0.3));
|
||
z-index: 1;
|
||
border-radius: 8rpx;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
&:hover .slanted-block {
|
||
height: 20rpx;
|
||
background: linear-gradient(90deg, rgba(74, 140, 255, 0.8), rgba(128, 179, 255, 0.5));
|
||
}
|
||
}
|
||
}
|
||
|
||
.interact_body {
|
||
width: 100%;
|
||
margin-top: 20rpx;
|
||
|
||
.body_item {
|
||
margin: 0 auto 40rpx;
|
||
background: #fff;
|
||
border-radius: 24rpx;
|
||
padding: 30rpx;
|
||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
|
||
|
||
.item_header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding-bottom: 30rpx;
|
||
border-bottom: 1rpx solid #f5f5f5;
|
||
|
||
.left_section {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.avatar {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
border-radius: 50%;
|
||
margin-right: 20rpx;
|
||
border: 2rpx solid #f0f0f0;
|
||
}
|
||
|
||
.info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
.name {
|
||
font-size: 30rpx;
|
||
color: #333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.date {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
margin-top: 8rpx;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.body_content {
|
||
padding: 30rpx 0;
|
||
|
||
h3 {
|
||
font-weight: 600;
|
||
height: 80rpx;
|
||
line-height: 80rpx;
|
||
color: #333;
|
||
font-size: 34rpx;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.content_font {
|
||
font-weight: normal;
|
||
color: #555;
|
||
font-size: 28rpx;
|
||
line-height: 48rpx;
|
||
margin-top: 20rpx;
|
||
}
|
||
|
||
.content_img {
|
||
width: 100%;
|
||
height: 400rpx;
|
||
margin: 40rpx 0;
|
||
border-radius: 16rpx;
|
||
overflow: hidden;
|
||
background: #f5f5f5;
|
||
|
||
image {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 评论输入框区域 */
|
||
.comment_input_area {
|
||
display: flex;
|
||
align-items: center;
|
||
margin: 30rpx 0;
|
||
padding: 20rpx 0;
|
||
border-top: 1rpx solid #f5f5f5;
|
||
border-bottom: 1rpx solid #f5f5f5;
|
||
|
||
.comment_input {
|
||
flex: 1;
|
||
height: 80rpx;
|
||
background: #f8f8f8;
|
||
border-radius: 40rpx;
|
||
padding: 0 30rpx;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.submit_btn {
|
||
width: 140rpx;
|
||
height: 80rpx;
|
||
line-height: 80rpx;
|
||
background: #4a8cff;
|
||
color: #fff;
|
||
border-radius: 40rpx;
|
||
margin-left: 20rpx;
|
||
font-size: 28rpx;
|
||
font-weight: normal;
|
||
}
|
||
}
|
||
|
||
/* 评论列表 */
|
||
.comment_list {
|
||
margin-top: 20rpx;
|
||
|
||
.comment_title {
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 30rpx;
|
||
padding-left: 10rpx;
|
||
}
|
||
|
||
.comment_item {
|
||
display: flex;
|
||
padding: 30rpx 0;
|
||
border-bottom: 1rpx solid #f5f5f5;
|
||
|
||
.comment_avatar {
|
||
width: 70rpx;
|
||
height: 70rpx;
|
||
border-radius: 50%;
|
||
margin-right: 20rpx;
|
||
border: 2rpx solid #f0f0f0;
|
||
}
|
||
|
||
.comment_content {
|
||
flex: 1;
|
||
|
||
.comment_info {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 10rpx;
|
||
|
||
.comment_user {
|
||
font-size: 28rpx;
|
||
color: #4a8cff;
|
||
font-weight: 500;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.comment_time {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
.comment_text {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
line-height: 1.6;
|
||
margin-bottom: 20rpx;
|
||
|
||
.reply_to {
|
||
color: #4a8cff;
|
||
margin-right: 10rpx;
|
||
}
|
||
}
|
||
|
||
.comment_actions {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.reply_btn,
|
||
.like_btn {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
margin-right: 30rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.like_icon {
|
||
width: 28rpx;
|
||
height: 28rpx;
|
||
margin-right: 8rpx;
|
||
}
|
||
}
|
||
|
||
.reply_btn {
|
||
&:active {
|
||
color: #4a8cff;
|
||
}
|
||
}
|
||
|
||
.like_btn {
|
||
&:active {
|
||
color: #ff4d4f;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 回复输入框 */
|
||
.reply_input_area {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-top: 20rpx;
|
||
padding: 20rpx 0;
|
||
|
||
.reply_input {
|
||
flex: 1;
|
||
height: 70rpx;
|
||
background: #f8f8f8;
|
||
border-radius: 35rpx;
|
||
padding: 0 30rpx;
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.submit_btn {
|
||
width: 120rpx;
|
||
height: 70rpx;
|
||
line-height: 70rpx;
|
||
background: #4a8cff;
|
||
color: #fff;
|
||
border-radius: 35rpx;
|
||
margin-left: 20rpx;
|
||
font-size: 26rpx;
|
||
font-weight: normal;
|
||
}
|
||
}
|
||
|
||
/* 子评论 */
|
||
.child_comments {
|
||
margin-top: 20rpx;
|
||
padding-left: 20rpx;
|
||
border-left: 4rpx solid #f0f0f0;
|
||
|
||
.child_comment_item {
|
||
display: flex;
|
||
padding: 25rpx 0;
|
||
border-bottom: 1rpx dashed #f0f0f0;
|
||
|
||
&:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.child_comment_avatar {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
border-radius: 50%;
|
||
margin-right: 20rpx;
|
||
border: 2rpx solid #f0f0f0;
|
||
}
|
||
|
||
.child_comment_content {
|
||
flex: 1;
|
||
|
||
.comment_info {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 8rpx;
|
||
|
||
.comment_user {
|
||
font-size: 26rpx;
|
||
color: #4a8cff;
|
||
font-weight: 500;
|
||
margin-right: 15rpx;
|
||
}
|
||
|
||
.comment_time {
|
||
font-size: 22rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
.comment_text {
|
||
font-size: 26rpx;
|
||
color: #555;
|
||
line-height: 1.5;
|
||
margin-bottom: 15rpx;
|
||
}
|
||
|
||
.comment_actions {
|
||
|
||
.reply_btn,
|
||
.like_btn {
|
||
font-size: 22rpx;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.view_more_replies {
|
||
font-size: 24rpx;
|
||
color: #4a8cff;
|
||
padding: 15rpx 0;
|
||
text-align: center;
|
||
|
||
&:active {
|
||
opacity: 0.8;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.no_comments {
|
||
text-align: center;
|
||
color: #999;
|
||
font-size: 28rpx;
|
||
padding: 60rpx 0;
|
||
background: #fafafa;
|
||
border-radius: 12rpx;
|
||
margin-top: 30rpx;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style> |