Browse Source

refactor(comment): 提取评论发布功能为独立组件并优化交互

将评论发布功能从commentList和commentDetail中提取为独立的commentPublish组件
优化评论发布交互流程,直接打开弹窗而非显示输入框
统一处理评论发布成功后的回调逻辑
master
前端-胡立永 2 weeks ago
parent
commit
395e230c18
3 changed files with 271 additions and 266 deletions
  1. +29
    -95
      pages_order/comment/commentDetail.vue
  2. +72
    -171
      pages_order/components/list/comment/commentList.vue
  3. +170
    -0
      pages_order/components/list/comment/commentPublish.vue

+ 29
- 95
pages_order/comment/commentDetail.vue View File

@ -98,25 +98,18 @@
<text @click="loadMoreReplies">加载更多</text>
</view>
<!-- 回复输入框 -->
<view class="reply-input-container" v-if="showInput">
<view class="input-wrapper">
<input
class="reply-input"
v-model="replyContent"
:placeholder="replyPlaceholder"
focus
confirm-type="send"
@confirm="submitReply"
/>
<button class="send-btn" :disabled="!replyContent.trim()" @click="submitReply">发送</button>
</view>
</view>
<!-- 评论发布组件 -->
<commentPublish ref="commentPublish" :params="commentParams" :placeholder="replyPlaceholder" @success="handleCommentSuccess" />
</view>
</template>
<script>
import commentPublish from '../components/list/comment/commentPublish.vue'
export default {
components: {
commentPublish
},
data() {
return {
commentId: '', // ID
@ -134,13 +127,23 @@
totalReplies: 0,
//
showInput: false,
replyContent: '',
replyToId: '', // ID
replyToUserName: '', //
replyPlaceholder: '写回复...'
}
},
computed: {
//
commentParams() {
return {
type: this.sourceType,
orderId: this.sourceId,
pid: this.commentId,
replyToId: this.replyToId,
replyToUserName: this.replyToUserName
}
}
},
onLoad(options) {
//
if (options.id) {
@ -219,51 +222,23 @@
this.loadReplies();
},
//
//
showReplyInput(commentId, userName = '') {
this.showInput = true;
this.replyToId = commentId;
this.replyToUserName = userName;
this.replyPlaceholder = userName ? `回复 @${userName}` : '写回复...';
this.replyContent = '';
//
this.$refs.commentPublish.open();
},
//
submitReply() {
if (!this.replyContent.trim()) return;
//
handleCommentSuccess() {
//
this.page = 1;
this.loadReplies();
// API
this.$api('addComment', {
userValue: this.replyContent,
pid: this.commentId,
replyToId: this.replyToId,
replyToUserName: this.replyToUserName,
type: this.sourceType,
orderId: this.sourceId
}, res => {
if (res.code === 200) {
//
this.replyContent = '';
this.showInput = false;
//
this.page = 1;
this.loadReplies();
//
this.totalReplies++;
uni.showToast({
title: '回复成功',
icon: 'success'
});
} else {
uni.showToast({
title: res.message || '回复失败',
icon: 'none'
});
}
});
//
this.totalReplies++;
},
//
@ -579,45 +554,4 @@
color: #666;
}
}
.reply-input-container {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #fff;
padding: 20rpx 30rpx;
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
z-index: 100;
padding-bottom: env(safe-area-inset-bottom);
.input-wrapper {
display: flex;
align-items: center;
.reply-input {
flex: 1;
height: 70rpx;
background-color: #f5f5f5;
border-radius: 35rpx;
padding: 0 30rpx;
font-size: 28rpx;
}
.send-btn {
margin-left: 20rpx;
background-color: $uni-color-primary;
color: #fff;
font-size: 28rpx;
height: 70rpx;
line-height: 70rpx;
padding: 0 30rpx;
border-radius: 35rpx;
&[disabled] {
background-color: #cccccc;
}
}
}
}
</style>

+ 72
- 171
pages_order/components/list/comment/commentList.vue View File

@ -1,184 +1,85 @@
<template>
<view class="commemt">
<view class="comment-list">
<commentItem
v-for="(item,index) in list"
:key="index"
:parentId="item.id"
:sourceType="params.type"
:sourceId="params.orderId"
:item="item" />
</view>
<view class="commemt">
<view class="comment-list">
<commentItem v-for="(item, index) in list" :key="index" :parentId="item.id" :sourceType="params.type"
:sourceId="params.orderId" :item="item" />
</view>
<view class="submit-box">
<view class="top">
<button
class="share"
open-type="share">
<uv-icon
color="#00cf05"
size="50rpx"
name="weixin-fill"></uv-icon>
</button>
<input type="text"
disabled
@click="$refs.popup.open('bottom')"
:placeholder="'评论给' + params.name"
v-model="form.userValue"/>
<!-- <view class="submit"
@click="submit">
发布
</view> -->
</view>
</view>
<uv-popup ref="popup" :round="30">
<view class="popup">
<view class="content-input">
<uv-textarea
v-model="form.userValue"
:maxlength="200"
autoHeight
count
focus
:placeholder="'评论给' + params.name"></uv-textarea>
</view>
<view class="images box">
<uv-upload
:fileList="fileList"
:maxCount="imageMax"
multiple
width="150rpx"
height="150rpx"
@delete="deleteImage"
@afterRead="afterRead"
:previewFullImage="true"></uv-upload>
</view>
<view class="uni-color-btn"
@click="submit">
发布
</view>
</view>
</uv-popup>
</view>
<view class="submit-box">
<view class="top">
<button class="share" open-type="share">
<uv-icon color="#00cf05" size="50rpx" name="weixin-fill"></uv-icon>
</button>
<input type="text" disabled @click="openCommentPublish" :placeholder="'评论给' + params.name" />
</view>
</view>
<!-- 评论发布组件 -->
<commentPublish ref="commentPublish" :params="params" :placeholder="'评论给' + params.name" @success="handleCommentSuccess" />
</view>
</template>
<script>
import commentItem from './commentItem.vue'
export default {
components: {
commentItem,
},
props: ['list', 'params'],
data() {
return {
form : {},
imageMax : 9,
fileList : [],
}
},
methods: {
submit(){
let data = {
...this.form,
...this.params,
}
if (this.$utils.verificationAll(data, {
userValue: '说点什么吧',
type: '缺少type',
orderId: '缺少orderId',
})) {
return
}
data.userImage = this.fileList.map((item) => item.url).join(",")
this.$api('addComment', data, res => {
if(res.code == 200){
this.$refs.popup.close()
this.form.userValue = ''
uni.showToast({
title: '发布成功!',
icon: 'none'
})
this.$emit('getData')
}
})
},
deleteImage(e){
this.fileList.splice(e.index, 1)
},
afterRead(e){
let self = this
e.file.forEach(file => {
self.$Oss.ossUpload(file.url).then(url => {
self.fileList.push({
url
})
})
})
},
}
}
import commentItem from './commentItem.vue'
import commentPublish from './commentPublish.vue'
export default {
components: {
commentItem,
commentPublish,
},
props: ['list', 'params'],
data() {
return {}
},
methods: {
//
openCommentPublish() {
this.$refs.commentPublish.open()
},
//
handleCommentSuccess() {
this.$emit('getData')
}
}
}
</script>
<style scoped lang="scss">
.commemt{
padding-bottom: env(safe-area-inset-bottom);
}
.comment-list {
margin-top: 20rpx;
padding-bottom: 150rpx;
}
.commemt {
padding-bottom: env(safe-area-inset-bottom);
}
.submit-box {
position: fixed;
bottom: 0;
left: 0;
background-color: #fff;
width: 100%;
box-shadow: 0 0 6rpx 6rpx #00000011;
padding-bottom: env(safe-area-inset-bottom);
.comment-list {
margin-top: 20rpx;
padding-bottom: 150rpx;
}
.top {
align-items: center;
display: flex;
justify-content: center;
.submit-box {
position: fixed;
bottom: 0;
left: 0;
background-color: #fff;
width: 100%;
box-shadow: 0 0 6rpx 6rpx #00000011;
padding-bottom: env(safe-area-inset-bottom);
input {
background-color: #f3f3f3;
width: 460rpx;
height: 40rpx;
border-radius: 40rpx;
margin: 20rpx;
padding: 20rpx 30rpx;
font-size: 28rpx;
}
.top {
align-items: center;
display: flex;
justify-content: center;
.submit {}
}
}
.popup{
.content-input{
min-height: 400rpx;
}
.box{
padding: 0 20rpx;
}
.images{
display: flex;
flex-wrap: wrap;
padding: 20rpx;
}
}
input {
background-color: #f3f3f3;
width: 460rpx;
height: 40rpx;
border-radius: 40rpx;
margin: 20rpx;
padding: 20rpx 30rpx;
font-size: 28rpx;
}
}
}
</style>

+ 170
- 0
pages_order/components/list/comment/commentPublish.vue View File

@ -0,0 +1,170 @@
<template>
<uv-popup ref="popup" :round="30">
<view class="comment-publish">
<view class="content-input">
<uv-textarea v-model="form.userValue" :maxlength="200" autoHeight count focus
:placeholder="placeholder"></uv-textarea>
</view>
<view class="images box">
<uv-upload :fileList="fileList" :maxCount="imageMax" multiple width="150rpx" height="150rpx"
@delete="deleteImage" @afterRead="afterRead" :previewFullImage="true"></uv-upload>
</view>
<view class="uni-color-btn" @click="submit">
发布
</view>
</view>
</uv-popup>
</template>
<script>
export default {
name: 'CommentPublish',
props: {
//
params: {
type: Object,
default: () => ({})
},
//
placeholder: {
type: String,
default: '说点什么吧...'
}
},
data() {
return {
form: {
userValue: ''
},
imageMax: 9,
fileList: [],
}
},
methods: {
//
open() {
this.$refs.popup.open('bottom')
},
//
close() {
this.$refs.popup.close()
},
async submit() {
await this.onSubscribeMessageTap()
let data = {
...this.form,
...this.params,
}
if (this.$utils.verificationAll(data, {
userValue: '说点什么吧',
type: '缺少type',
orderId: '缺少orderId',
})) {
return
}
data.userImage = this.fileList.map((item) => item.url).join(",")
this.$api('addComment', data, res => {
if (res.code == 200) {
this.close()
this.resetForm()
uni.showToast({
title: '发布成功!',
icon: 'none'
})
this.$emit('success')
}
})
},
//
resetForm() {
this.form.userValue = ''
this.fileList = []
},
deleteImage(e) {
this.fileList.splice(e.index, 1)
},
afterRead(e) {
let self = this
e.file.forEach(file => {
self.$Oss.ossUpload(file.url).then(url => {
self.fileList.push({
url
})
})
})
},
//
onSubscribeMessageTap() {
return new Promise((resolve, reject) => {
let templateIds = [
'uXZnHWrjtcX9JHlnMpdlWmzgJp71sKxCRiMn3TrE-EE',
'gTzGpOfJcYxtbvPG9OHnhbureKz5XLG8NPyECUGb2lw',
];
wx.requestSubscribeMessage({
tmplIds: templateIds, // ID
success(res) {
resolve(res)
console.log('订阅消息调用成功', res);
// res[tmplId] ID
// res['your_template_id_1'] === 'accept'
templateIds.forEach(tmplId => {
if (res[tmplId] === 'accept') {
console.log(`用户同意订阅模板ID:${tmplId}`);
//
} else if (res[tmplId] === 'reject') {
console.log(`用户拒绝订阅模板ID:${tmplId}`);
} else {
console.log(`用户对该模板ID的订阅请求:${res[tmplId]}`); // 'ban'
}
});
},
fail(err) {
resolve(res)
console.error('订阅消息调用失败', err);
}
});
})
},
}
}
</script>
<style scoped lang="scss">
.comment-publish {
.content-input {
min-height: 400rpx;
}
.box {
padding: 0 20rpx;
}
.images {
display: flex;
flex-wrap: wrap;
padding: 20rpx;
}
.uni-color-btn {
background-color: $uni-color-primary;
color: #fff;
text-align: center;
padding: 20rpx;
margin: 20rpx;
border-radius: 10rpx;
font-size: 32rpx;
}
}
</style>

Loading…
Cancel
Save