评论组件完成

This commit is contained in:
aixianling
2022-05-25 17:04:52 +08:00
parent f36e184fb7
commit 8f40ac4dd4
5 changed files with 424 additions and 170 deletions

View File

@@ -1,207 +1,178 @@
<template>
<div class="AiComment">
<div class="comments flex-row">
<div class="comments-box" @click="showCommentBox">{{ boxContent }}</div>
<img src="./static/comment.svg" @click="showCommentList" alt=""/>
<text>{{ commentCount || 0 }}</text>
<div class="pageTitle flex">
评论
<div class="mar-l16" v-text="total"/>
</div>
<div class="modalWrapper" v-if="commentBoxPopup" :class="{clickClose:!modelClickClose}"
@click="commentBoxPopup=false"/>
<div class="commentBox" v-if="commentBoxPopup" :style="{bottom:marginBottom+ 'px'}">
<textarea v-model="content" placeholder="写下你的想法…" maxlength="300" :focus="focus" @focus="getMarginBottom"
@blur="marginBottom=0" :adjust-position="false" fixed/>
<view class="flex-row form-submit">
<div>{{ `字数 ${wordCount || 0} / 300` }}</div>
<button @click="submitComment" :disabled="wordCount == 0">发布</button>
</view>
<div class="flex item" v-for="row in list" :key="row.id">
<img :src="row.avatar"/>
<div class="fill">
<div class="flex font-32">
<div class="fill font600 font-28" v-text="row.name"/>
<AiThumbsUp :bid="row.id" type="comment" :count.sync="row.hotCount"/>
</div>
<div class="font-32 mar-t8 mar-b24" v-text="row.content"/>
<div class="flex mar-b24">
<div class="color-999" v-text="[row.areaName,row.commentTime].join(' ')"/>
<comment-editor class="mar-l16" :bid="row.id" type="2">回复TA</comment-editor>
</div>
<div v-if="getArrayLength(row.replyList)>0" class="replyList">
<div v-if="row.showAllReply">
<div class="flex color-666 mar-t8" v-for="reply in row.replyList" :key="reply.id">
<div class="font600" v-text="reply.name+''"/>
<div v-text="reply.content"/>
</div>
<div v-if="getArrayLength(row.replyList)>2" class="color-687DA6 mar-t8" v-text="`收起`" @click="handleExpand(row)"/>
</div>
<div v-else>
<div class="flex color-666 mar-t8" v-for="reply in getReplies(row.replyList)" :key="reply.id">
<div class="font600" v-text="reply.name+''"/>
<div v-text="reply.content"/>
</div>
<div v-if="getArrayLength(row.replyList)>2" class="color-687DA6 mar-t8" v-text="`查看全部${getArrayLength(row.replyList)}条回复 >`"
@click="handleExpand(row)"/>
</div>
</div>
</div>
</div>
<comment-editor class="fixedBottom" :bid="bid" :comment-count="total"/>
<u-gap height="128"/>
</div>
</template>
<script>
import CommentEditor from "./commentEditor";
import AiThumbsUp from "../AiThumbsUp/AiThumbsUp";
export default {
name: "AiComment",
components: {AiThumbsUp, CommentEditor},
props: {
needLogin: Boolean,
customLogin: Boolean,
commentCount: Number,
modelClickClose: {type: Boolean, default: true}
},
computed: {
wordCount() {
return this.content.length || 0
},
boxContent() {
return this.content || "我也说两句..."
},
isLogin() {
return Boolean(uni.getStorageSync('token'))
},
bid: {default: ""}
},
data() {
return {
content: "",
marginBottom: 0,
commentBoxPopup: false,
focus: false
list: [],
current: 1,
total: 0
}
},
methods: {
showCommentBox() {
if (this.customLogin) {
this.$emit("login", flag => this.commentBoxPopup = flag)
} else if (this.needLogin) {
if (this.isLogin) {
this.commentBoxPopup = true
} else {
this.$dialog.confirm({
content: '您还未登陆',
confirmText: '去登录'
}).then(() => {
uni.switchTab({url: '/pages/mine/mine'})
}).catch(() => {
})
}
} else {
this.commentBoxPopup = true
getComments() {
let {current, total, bid: contentId} = this
if (!total || this.list.length < total) {
this.$instance.post("/app/appcontentcomment/list", null, {
params: {current, contentId}
}).then(res => {
if (res?.data) {
res.data.records.map(e => e.showAllReply = false)
this.list = [current == 1 ? [] : this.list, res.data.records].flat()
this.total = res.data.total
}
})
}
},
submitComment() {
this.commentBoxPopup = false
this.$emit("submitComment", this.content)
this.content = ""
getReplies(list, showAll) {
return list?.slice(0, showAll ? this.getArrayLength(list) : 2) || []
},
showCommentList() {
this.commentBoxPopup = false
this.$emit("showCommentList")
getArrayLength(list) {
return list?.length || 0
},
getMarginBottom({detail}) {
this.marginBottom = detail.height
this.focus = true
handleExpand(row) {
console.log(row)
row.showAllReply = !row.showAllReply
}
},
created() {
this.getComments()
uni.$on("moreComments", flag => {
flag ? this.current = 1 : this.current++
this.getComments()
})
},
destroyed() {
uni.$off("moreComments")
}
}
</script>
<style lang="scss" scoped>
.AiComment {
.comments {
width: 100%;
height: 112px;
background: #fff;
.item {
padding: 24px 32px;
box-sizing: border-box;
position: fixed;
bottom: 0;
background: #f7f7f7;
align-items: flex-start;
color: #333;
font-size: 26px;
.comments-box {
width: 580px;
& > img {
height: 64px;
line-height: 64px;
background-color: #fff;
color: #666;
font-size: 26px;
padding-left: 16px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 64px;
border-radius: 50%;
margin-right: 16px;
}
image {
width: 52px;
height: 52px;
margin-left: 16px;
vertical-align: middle;
}
text {
color: #666666;
font-size: 28px;
line-height: 60px;
.content {
margin: 8px 0 24px;
}
}
.modalWrapper {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, .6);
z-index: 9;
&.clickClose {
pointer-events: none;
}
.font600 {
font-weight: 600;
}
.commentBox {
width: 100%;
height: 288px;
background-color: #fff;
padding: 32px 32px 24px 26px;
box-sizing: border-box;
position: fixed;
bottom: 0;
z-index: 99;
textarea {
width: 100%;
height: 144px;
color: #666;
font-size: 26px;
background: #F7F7F7;
border-radius: 16px;
padding: 16px;
box-sizing: border-box;
&::placeholder {
font-size: inherit;
}
}
.form-submit {
margin-top: 24px;
height: 64px;
justify-content: space-between;
align-items: center;
color: #999;
font-size: 24px;
button {
width: 144px;
height: 64px;
background-color: #135AB8;
color: #fff;
font-size: 24px;
border-radius: 32px;
line-height: 64px;
text-align: center;
margin: unset;
&[disabled] {
color: #999;
background-color: #f7f7f7;
font-size: 28px;
border: 0;
}
&:active {
opacity: .8;
}
&:after {
border: none;
}
}
}
.font-32 {
font-size: 32px;
}
.flex-row {
display: flex;
flex-direction: row;
.font-28 {
font-size: 28px;
}
.mar-t8 {
margin-top: 8px;
}
.mar-b24 {
margin-bottom: 24px;
}
.mar-r16 {
margin-right: 16px;
}
.mar-l16 {
margin-left: 16px;
}
.color-999 {
color: #999;
}
.color-666 {
color: #666;
}
.color-687DA6 {
color: #687DA6;
}
.replyList {
padding: 8px 16px 16px;
background: #F4F5FA;
border-radius: 8px;
font-size: 28px;
}
.pageTitle {
height: 100px;
padding: 0 32px;
font-size: 34px;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #333333;
}
}
</style>

View File

@@ -0,0 +1,217 @@
<template>
<section class="commentEditor">
<div v-if="$slots.default" @click="showCommentBox">
<slot/>
</div>
<div v-else class="comments flex-row">
<div class="comments-box" @click="showCommentBox">{{ boxContent }}</div>
<img src="./static/comment.svg" alt=""/>
<text>{{ commentCount || 0 }}</text>
</div>
<div class="modalWrapper" v-if="commentBoxPopup" :class="{clickClose:!modelClickClose}"
@click="commentBoxPopup=false"/>
<div class="commentBox" v-if="commentBoxPopup" :style="{bottom:marginBottom+ 'px'}">
<textarea v-model="content" placeholder="写下你的想法…" maxlength="300" :focus="focus" @focus="getMarginBottom"
@blur="marginBottom=0" :adjust-position="false" fixed/>
<view class="flex-row form-submit">
<div>{{ `字数 ${wordCount || 0} / 300` }}</div>
<button @click="submitComment" :disabled="wordCount == 0">发布</button>
</view>
</div>
</section>
</template>
<script>
export default {
name: "commentEditor",
props: {
bid: {default: ""},
type: {default: 1},
needLogin: Boolean,
customLogin: Boolean,
commentCount: Number,
modelClickClose: {type: Boolean, default: true}
},
computed: {
wordCount() {
return this.content.length || 0
},
boxContent() {
return this.content || "我也说两句..."
},
isLogin() {
return Boolean(uni.getStorageSync('token'))
},
},
data() {
return {
content: "",
marginBottom: 0,
commentBoxPopup: false,
focus: false
}
},
methods: {
showCommentBox() {
if (this.customLogin) {
this.$emit("login", flag => this.commentBoxPopup = flag)
} else if (this.needLogin) {
if (this.isLogin) {
this.commentBoxPopup = true
} else {
this.$dialog.confirm({
content: '您还未登陆',
confirmText: '去登录'
}).then(() => {
uni.switchTab({url: '/pages/mine/mine'})
}).catch(() => {
})
}
} else {
this.commentBoxPopup = true
}
},
submitComment() {
let {content, type, bid: contentId} = this
this.$instance.post("/app/appcontentcomment/addByApplet", {content, type, contentId}).then(res => {
if (res?.code == 0) {
this.$u.toast("提交成功!")
this.commentBoxPopup = false
this.content = ""
uni.$emit("moreComments", 1)//刷新评论列表
}
})
},
getMarginBottom({detail}) {
this.marginBottom = detail.height
this.focus = true
}
}
}
</script>
<style lang="scss" scoped>
.commentEditor {
font-family: PingFangSC-Regular, PingFang SC;
.comments {
width: 100%;
height: 128px;
padding: 24px 32px;
box-sizing: border-box;
position: fixed;
bottom: 0;
background: #fff;
border-top: 1px solid #eee;
.comments-box {
width: 580px;
height: 80px;
line-height: 80px;
background-color: #F4F5FA;
color: #666;
font-size: 32px;
padding-left: 32px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
border-radius: 44px;
}
image {
width: 52px;
height: 52px;
margin-left: 16px;
vertical-align: middle;
}
text {
color: #666666;
font-size: 28px;
line-height: 60px;
}
}
.modalWrapper {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, .6);
z-index: 9;
&.clickClose {
pointer-events: none;
}
}
.commentBox {
width: 100vw;
height: 288px;
background-color: #fff;
padding: 32px 32px 24px 26px;
box-sizing: border-box;
position: fixed;
left: 0;
bottom: 0;
z-index: 99;
textarea {
width: 100%;
height: 144px;
color: #666;
font-size: 26px;
background: #F7F7F7;
border-radius: 16px;
padding: 16px;
box-sizing: border-box;
&::placeholder {
font-size: inherit;
}
}
.form-submit {
margin-top: 24px;
height: 64px;
justify-content: space-between;
align-items: center;
color: #999;
font-size: 24px;
button {
width: 144px;
height: 64px;
background-color: #135AB8;
color: #fff;
font-size: 24px;
border-radius: 32px;
line-height: 64px;
text-align: center;
margin: unset;
&[disabled] {
color: #999;
background-color: #f7f7f7;
font-size: 28px;
border: 0;
}
&:active {
opacity: .8;
}
&:after {
border: none;
}
}
}
}
.flex-row {
display: flex;
flex-direction: row;
}
}
</style>

View File

@@ -18,8 +18,6 @@
<div class="files" v-if="detail.contentType==1 && detail.files && detail.files.length">
<video class="file-img" :src="file.url" v-for="(file,index) in detail.files" :key="index"/>
</div>
<div v-if="comment" class="comments"/>
</section>
</template>
@@ -30,7 +28,6 @@ export default {
props: {
title: {default: ""},
detail: {default: () => ({})},
comment: Boolean
},
methods: {
preview(index) {
@@ -42,8 +39,8 @@ export default {
<style lang="scss" scoped>
.AiDetail {
min-height: 100vh;
background: #ffffff;
padding-bottom: 80px;
background: #fff;
.header {
.title {

View File

@@ -0,0 +1,62 @@
<template>
<section class="AiThumbsUp flex" :class="{checked}" @click.native="handleClick">
<div class="count" v-text="count||0"/>
<u-icon :name="thumbIcon"/>
</section>
</template>
<script>
export default {
name: "AiThumbsUp",
props: {
bid: {default: ""},
count: {default: 0},
btn: Boolean,
type: {default: "content"},
action: {default: ""}
},
computed: {
thumbIcon() {
return this.checked ? "thumb-up-fill" : "thumb-up"
}
},
data() {
return {
checked: false,
actions: {
content: "/app/appcontentinfo/supportById",
comment: "/app/appcontentcomment/supportById",
}
}
},
methods: {
handleClick() {
if (!this.checked) {
let {action, type, actions, bid: id} = this
this.$instance.post(action || actions[type], null, {
params: {id}
}).then(res => {
if (res?.code == 0) {
this.checked = true
this.$emit("update:count", ++this.count)
}
})
}
}
}
}
</script>
<style lang="scss" scoped>
.AiThumbsUp {
color: #666;
&.checked {
color: #2D7DFF;
}
.count {
margin-right: 8px;
}
}
</style>

View File

@@ -1,14 +1,19 @@
<template>
<section class="contentDetail">
<AiDetail :detail="detail" :props="props"/>
<u-gap height="16"/>
<AiComment v-if="detail.id" :bid="detail.id"/>
</section>
</template>
<script>
import AiComment from "dvcp-wui/AiComment/AiComment";
export default {
name: "contentDetail",
appName:"内容详情",
components: {AiComment},
appName: "内容详情",
data() {
return {
detail: {title: "内容详情"},
@@ -35,12 +40,14 @@ export default {
})
},
},
onShareAppMessage() {
return {
title: this.detail.title,
path: '/mods/AppContent/contentDetail?id=' + this.id
};
},
onReachBottom() {
uni.$emit("moreComments")
}
}
</script>