hookehuyr

✨ feat(作品详情页): 留言相关API联调

......@@ -53,14 +53,13 @@
import icon_x from '@images/x.png'
import icon_y from '@images/y.png'
import MyButton from '@/components/MyButton/index.vue'
import { Toast } from 'vant';
import { ref, reactive, onMounted } from 'vue'
// const props = defineProps({
// showPopup: Boolean
// })
const message = ref('')
onMounted(() => {
})
</script>
......@@ -70,7 +69,8 @@ export default {
props: ['showPopup', 'type'],
data () {
return {
show: false
show: false,
message: ''
}
},
mounted () {
......@@ -92,8 +92,13 @@ export default {
this.show = false;
},
submitComment () {
this.$emit('on-close', false)
if (this.message) {
this.show = false;
this.$emit('on-submit', this.message);
this.message = '';
} else {
Toast.fail('留言不能为空');
}
}
}
}
......
<template>
<van-popup
v-model:show="show"
:close-on-click-overlay="false"
round
position="bottom"
:style="{ height: '70%' }"
>
<van-popup v-model:show="show" :close-on-click-overlay="false" round position="bottom" :style="{ height: '70%' }">
<div class="van-hairline--bottom">
<van-row>
<van-col span="4" @click="refreshBtn">
<van-col span="4" @click="onReload">
<div style="padding: 1rem; text-align: center;">
<van-icon :name="icon_x" size="1.25rem" />
</div>
</van-col>
<van-col span="16" style="color: #222222; text-align: center; line-height: 3;">
<span>12条回复</span>
<span>{{ data.total }}条回复</span>
</van-col>
<van-col span="4" @click="closeBtn">
<div style="padding: 1rem;">
......@@ -23,46 +17,30 @@
</van-col>
</van-row>
</div>
<van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad" :immediate-check="false">
<template v-for="(item, key) in replyList" :key="key">
<div class="comment-wrapper">
<van-row style="font-size: 0.9rem;">
<van-col span="4">
<van-image round width="3rem" height="3rem" src="https://cdn.jsdelivr.net/npm/@vant/assets/cat.jpeg" />
<van-image round width="3rem" height="3rem" :src="item.avatar" />
</van-col>
<van-col span="16">
<p>是妮妮吖~</p>
<p>杨浦民办科技幼稚园</p>
<van-col span="14">
<p>{{ item.name }}</p>
<p>{{ item.kg_name }}</p>
</van-col>
<van-col span="4" style="text-align: center;">
<van-col span="6" style="text-align: right;">
<p style="color: #333333;">回复</p>
<p>2-25</p>
<p>{{ item.comment_time }}</p>
</van-col>
</van-row>
<van-row>
<van-col offset="4">
<span style="color: #222222;">瑟日古娜小朋友表演的可真棒,感谢你的精彩演绎,希望有更多的小朋友能够学习到!</span>
</van-col>
</van-row>
</div>
<div class="comment-wrapper" style="background-color: #F7F7F7;">
<van-row style="font-size: 0.9rem;">
<van-col span="4">
<van-image round width="3rem" height="3rem" src="https://cdn.jsdelivr.net/npm/@vant/assets/cat.jpeg" />
</van-col>
<van-col span="16">
<p>是妮妮吖~</p>
<p>杨浦民办科技幼稚园</p>
</van-col>
<van-col span="4" style="text-align: center;" @click="setComment('222', 'reply')">
<p style="color: #333333;">回复</p>
<p>2-25</p>
</van-col>
</van-row>
<van-row>
<van-col offset="4">
<span style="color: #222222;">瑟日古娜小朋友表演的可真棒,感谢你的精彩演绎,希望有更多的小朋友能够学习到!</span>
<span style="color: #222222;">{{ item.note }}</span>
</van-col>
</van-row>
</div>
</template>
</van-list>
<comment-box :showPopup="showCommentBoxPopup" :type="commentType" @on-close="closeCommentBox"></comment-box>
</van-popup>
......@@ -75,6 +53,10 @@ import CommentBox from '@/components/CommentBox/index.vue'
import icon_x from '@images/x.png'
import icon_y from '@images/y.png'
import axios from '@/utils/axios';
import _ from 'lodash'
import { Toast } from 'vant';
import { ref, reactive, onMounted } from 'vue'
// const props = defineProps({
// showPopup: Boolean
......@@ -97,33 +79,74 @@ const closeCommentBox = (v) => { // 查看更多回复
showCommentBoxPopup.value = v;
}
onMounted(() => {
})
onMounted(() => {
})
</script>
<script>
export default {
props: ['showPopup'],
data () {
props: ['showPopup', 'data'],
data() {
return {
show: false
show: false,
replyList: [],
loading: false,
finished: false,
limit: 10,
offset: 0,
}
},
mounted () {
mounted() {
},
watch: {
showPopup (value, pre) {
showPopup(value, pre) {
if (value) {
this.show = value;
this.onReload()
}
}
},
methods: {
onClose () {
onLoad () {
// 异步更新数据
axios.get('/srv/?a=reply_list', {
params: {
comment_id: this.data.id,
limit: this.limit,
offset: this.offset
}
})
.then(res => {
if (res.data.code === 1) {
this.replyList = _.concat(this.replyList, res.data.data.replylist);
this.offset = this.replyList.length;
this.loading = false;
// 数据全部加载完成
if (!res.data.data.replylist.length) {
// 加载状态结束
this.finished = true;
}
} else {
console.warn(res);
Toast({
icon: 'close',
message: res.data.msg
});
}
})
.catch(err => {
console.error(err);
})
},
onReload () {
this.replyList = [];
this.offset = 0;
this.onLoad();
},
onClose() {
this.show = false;
},
refreshBtn () {},
closeBtn () {
closeBtn() {
this.$emit('on-close', false)
this.show = false;
}
......
......@@ -5,13 +5,17 @@ export const mainStore = defineStore('main', {
return {
msg: 'Hello world',
count: 0,
auth: false
auth: false,
comment_num: 0
};
},
getters: {},
actions: {
changeState (state: boolean) {
changeState (state) {
this.auth = state;
},
changeCommentNum (num) {
this.comment_num = num;
}
},
});
\ No newline at end of file
......
......@@ -24,7 +24,7 @@
<van-tab title="简介" :title-style="tabClass">
<div class="intro">{{ videoInfo.note }}</div>
</van-tab>
<van-tab :title="'留言 ' + videoInfo.comment_num" :title-style="tabClass" :to="'/client/videoDetail/comment?prod_id=' + $route.query.prod_id">
<van-tab :title="'留言 ' + comment_num" :title-style="tabClass" :to="'/client/videoDetail/comment?prod_id=' + $route.query.prod_id">
<router-view></router-view>
</van-tab>
</van-tabs>
......@@ -37,6 +37,9 @@
</template>
<script setup>
import { mainStore } from '@/store'
import { storeToRefs } from 'pinia'
import VideoDetail from '@/components/VideoDetail/index.vue'
import { ref, reactive, onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
......@@ -61,6 +64,11 @@ const tabClass = {
fontSize: '1rem'
}
// 处理主路由的留言数量问题
const store = mainStore()
// Pinia 解构方法:storeToRefs
const { comment_num } = storeToRefs(store)
const videoInfo = ref('');
onMounted(() => {
......@@ -81,6 +89,8 @@ onMounted(() => {
.then(res => {
if (res.data.code === 1) {
videoInfo.value = res.data.data;
// 动态调整留言数量
store.changeCommentNum(res.data.data.comment_num);
} else {
console.warn(res);
Toast({
......
<template>
<div class="">
<!-- 回复条数大于20才加载 后端需要给我总条数 -->
<template v-if="sum >= 20">
<van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
<div v-for="item in list" :key="item" :title="item">
{{ item }}
</div>
</van-list>
</template>
<template v-else>
<van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad" :immediate-check="false">
<template v-for="(item, key) in commentList" :key="key">
<div class="comment-wrapper">
<van-row style="font-size: 0.9rem;">
<van-col span="4">
<van-image round width="3rem" height="3rem" src="https://cdn.jsdelivr.net/npm/@vant/assets/cat.jpeg" />
<van-image round width="3rem" height="3rem" :src="item.avatar" />
</van-col>
<van-col span="16">
<p>是妮妮吖~</p>
<p>杨浦民办科技幼稚园</p>
<van-col span="14">
<p>{{ item.name }}</p>
<p>{{ item.kg_name }}</p>
</van-col>
<van-col span="4" style="text-align: center;">
<p @click="setComment('11', 'reply')" style="color: #333333;">回复</p>
<p>2-25</p>
<van-col span="6" style="text-align: right;">
<p @click="setComment(item, 'reply')" style="color: #333333;">回复</p>
<p>{{ item.comment_time }}</p>
</van-col>
</van-row>
<van-row>
<van-col offset="4">
<span style="color: #222222;">瑟日古娜小朋友表演的可真棒,感谢你的精彩演绎,希望有更多的小朋友能够学习到!</span>
<span style="color: #222222;">{{ item.note }}</span>
</van-col>
</van-row>
<van-row>
<van-col offset="4">
<div class="reply-wrapper">
<p><span>瑟日古娜(作者):</span><span class="content">谢谢您的表扬,我会继续加油的!</span></p>
<p><span>阿布日达 </span>回复<span> @瑟日古娜(作者):</span><span class="content">厉害的呀,棒!!</span></p>
<p @click="getMore()">共12条回复 ></p>
<van-col offset="4" span="20">
<div v-if="item.total" class="reply-wrapper">
<template v-for="(reply, index) in item.reply_list" :key="index">
<p v-if="reply.reply_to"><span>{{ reply.name }}</span>&nbsp;回复&nbsp;<span>@{{ reply.reply_to }}:</span><span class="content">{{ reply.note }}</span></p>
<p v-else><span>{{ reply.name }}:</span><span class="content">{{ reply.note }}</span></p>
</template>
<p v-if="item.total !== reply_limit" @click="getMore(item)">共{{ item.total }}条回复 ></p>
</div>
</van-col>
</van-row>
</div>
</template>
</van-list>
<div style="height: 5rem;"></div>
<div class="reply-btn" @click="setComment('222', 'comment')">
<div class="reply-btn" @click="setComment('', 'comment')">
<div class="text">写下你友善的留言</div>
</div>
</div>
<comment-list :showPopup="showCommentListPopup" @on-close="closeCommentList"></comment-list>
<comment-box :showPopup="showCommentBoxPopup" :type="commentType" @on-close="closeCommentBox"></comment-box>
<comment-list :showPopup="showCommentListPopup" :data="commentData" @on-close="closeCommentList"></comment-list>
<comment-box :showPopup="showCommentBoxPopup" :type="commentType" @on-submit="submitCommentBox" @on-close="closeCommentBox"></comment-box>
<!-- 写评论时,如果没有上传作品提示弹框 -->
<van-overlay :show="showNotice" z-index="1000">
......@@ -56,12 +52,14 @@
<p style="margin: 1rem; font-size: 1.15rem; font-weight: bold; color: #222222;">温馨提示</p>
</div>
<div style="color: #333333;">
<p>您还没有上传作品</p>
<!-- <p>您还没有上传作品</p>
<p>请返回书籍详情页,点击 <span style="font-weight: bold; color: #713610;">上传作品</span> 按钮</p>
<p>上传之后再留言</p>
<p>上传之后再留言</p> -->
<p>您还没有实名认证</p>
<p>请前往个人中心进行实名认证</p>
</div>
<div style="margin: 3rem 0;">
<my-button @on-click="closeNotice" type="primary">返回</my-button>
<my-button @on-click="closeNotice" type="primary">前往认证</my-button>
</div>
</div>
</div>
......@@ -69,48 +67,107 @@
</template>
<script setup>
import { mainStore } from '@/store'
import CommentList from '@/components/CommentList/index.vue'
import CommentBox from '@/components/CommentBox/index.vue'
import MyButton from '@/components/MyButton/index.vue'
import icon_me from '@images/icon-my@2x.png'
import icon_notice from '@images/que-tishi@2x.png'
import { ref, reactive, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import axios from '@/utils/axios';
import $ from 'jquery'
import _ from 'lodash'
import { Toast } from 'vant';
// 获取是否实名认证
import { idCard } from '@/composables/useValidIdCard.js'
const validIdCard = idCard();
const $route = useRoute();
const $router = useRouter();
const list = ref([]);
const sum = ref(0);
// 查询留言接口数据
const loading = ref(false);
const finished = ref(false);
const limit = ref(5)
const offset = ref(0)
const reply_limit = ref(3)
const commentList = ref([])
const onLoad = () => {
// 异步更新数据
// setTimeout 仅做示例,真实场景中一般为 ajax 请求
setTimeout(() => {
for (let i = 0; i < 10; i++) {
list.value.push(list.value.length + 1);
axios.get('/srv/?a=comment_list',{
params: {
prod_id: $route.query.prod_id,
limit: limit.value,
offset: offset.value,
reply_limit: reply_limit.value
}
// 加载状态结束
})
.then(res => {
if (res.data.code === 1) {
commentList.value = _.concat(commentList.value, res.data.data);
offset.value = commentList.value.length;
loading.value = false;
// 数据全部加载完成
if (list.value.length >= 100) {
if (!res.data.data.length) {
// 加载状态结束
finished.value = true;
}
}, 1000);
} else {
console.warn(res);
Toast({
icon: 'close',
message: res.data.msg
});
}
})
.catch(err => {
console.error(err);
})
};
const onReload = () => {
// TODO: 初始化列表数据,会使得列表滚到最上面
// 处理方法只能是插入相应的一条数据,这样就需要后台新增完成后,返回完整数据
commentList.value = [];
offset.value = 0;
onLoad();
const store = mainStore()
// 刷新主路由上面的留言数量
axios.get('/srv/?a=prod_info', {
params: {
prod_id: $route.query.prod_id
}
})
.then(res => {
if (res.data.code === 1) {
store.changeCommentNum(res.data.data.comment_num);
} else {
console.warn(res);
Toast({
icon: 'close',
message: res.data.msg
});
}
})
.catch(err => {
console.error(err);
})
}
// 回复消息列表模块
const showCommentListPopup = ref(false);
const getMore = (v) => { // 查看更多回复
const commentData = ref('')
// 查看更多回复
const getMore = (v) => {
showCommentListPopup.value = true;
commentData.value = v;
}
const closeCommentList = (v) => { // 查看更多回复
showCommentListPopup.value = v;
......@@ -122,26 +179,74 @@ const showNotice = ref(false)
const closeNotice = () => { // 关闭提示框回调
showNotice.value = false;
$router.push({
path: '/client/bookDetail'
path: '/me/index'
});
}
const flag = true; // 后台接口判断是否上传过作品
// 实际调试时,点击回复需要判断是否上传过作品
const setComment = (v, type) => { // 回复/评论
if (flag) {
/**
* 回复/评论 功能
* @param {*} v 单行评论数据
* @param {*} type 类型 comment 为评论/类型 reply 为回复
*/
const commentId = ref('')
const setComment = (v, type) => { //
if (validIdCard.can_use) {
showCommentBoxPopup.value = true;
commentType.value = type;
commentId.value = v.id;
} else {
showNotice.value = true;
}
}
const closeCommentBox = (v) => { // 查看更多回复
showCommentBoxPopup.value = v;
/**
* 提交留言回调
* @param {*} note 留言内容
*/
const submitCommentBox = (note) => {
let url = '';
let data = {}
// 判断是留言还是回复 动态调整接口名称
if (commentType.value === 'comment') {
url = 'add_comment';
data = {
prod_id: $route.query.prod_id,
note
}
} else {
url = 'add_reply';
data = {
comment_id: commentId.value,
note
}
}
axios.post(`/srv/?a=${url}`, data)
.then(res => {
if (res.data.code === 1) {
showCommentBoxPopup.value = false;
Toast.success('发布成功')
// 刷新列表
// onReload();
// 不能刷新,只能插入
} else {
console.warn(res);
Toast({
icon: 'close',
message: res.data.msg
});
}
})
.catch(err => {
console.error(err);
})
}
const closeCommentBox = (v) => { // 关闭留言框
showCommentBoxPopup.value = v;
}
onMounted(() => {
sum.value = 10; // 获取评论总条数,判断是否加载控件
onLoad();
})
</script>
......@@ -156,7 +261,6 @@ export default {
}
},
mounted() {
},
methods: {
......@@ -185,9 +289,10 @@ export default {
.reply-btn {
position: fixed;
bottom: 1rem;
bottom: 0;
left: 0;
right: 0;
background-color: white;
.text {
text-align: center;
......