507 lines
12 KiB
Vue
507 lines
12 KiB
Vue
<template>
|
||
<view class="comment_div">
|
||
<view class="message_div" v-for="(item, index) in message_list">
|
||
<view class="head_div">
|
||
<image-preview v-if="item.userIconImgId" class="img-box img" :src="item.userIconImgId"></image-preview>
|
||
<image v-else src="/static/images/me/default_user_avatar.png" class="img"></image>
|
||
</view>
|
||
<view class="msg_content">
|
||
<view class="title_div">
|
||
<view class="name">{{ item.userName }}</view>
|
||
<view class="title_tip">
|
||
<image
|
||
class="img"
|
||
v-if="item.bbsTag === 'ASK'"
|
||
src="@/static/images/courseDetail/ASK.png"
|
||
mode="widthFix"
|
||
></image>
|
||
<image
|
||
class="img"
|
||
v-if="item.bbsTag === 'SUG'"
|
||
src="@/static/images/courseDetail/SUG.png"
|
||
mode="widthFix"
|
||
></image>
|
||
</view>
|
||
<!-- <view class="title_tip">{{item.bbsTagDesc}}</view> -->
|
||
</view>
|
||
<view class="title">
|
||
{{ item.bbsContent }}
|
||
</view>
|
||
<view class="img_div pic-cell">
|
||
<image-preview
|
||
v-for="img in item.imgIdList"
|
||
@click="showPicture(item.imgIdList, img)"
|
||
:src="img"
|
||
class="pic-item"
|
||
mode="scaleToFill"
|
||
></image-preview>
|
||
</view>
|
||
<view class="time_and_reply">
|
||
<view class="time">{{ item.bbsTm.substr(0, 16) }}</view>
|
||
<view class="reply" @click="click_reply(item, item.bbsId, index)">回复</view>
|
||
</view>
|
||
<view class="show_close_div" v-if="item.children?.length" @click="item.show = !item.show">
|
||
<template v-if="item.show">
|
||
<view>收起</view>
|
||
<view class="back_div">
|
||
<view class="back-icon"></view>
|
||
</view>
|
||
</template>
|
||
<template v-else>
|
||
<view>展开{{ item.children?.length }}条回复</view>
|
||
<view class="back_div">
|
||
<view class="back-icon"></view>
|
||
</view>
|
||
</template>
|
||
</view>
|
||
<view class="children" v-if="item.show">
|
||
<view class="message_div" v-for="childrenItem in item.children">
|
||
<view class="head_div">
|
||
<image-preview
|
||
v-if="childrenItem.userIconImgId"
|
||
class="img-box img"
|
||
:src="childrenItem.userIconImgId"
|
||
></image-preview>
|
||
<image v-else src="/static/images/me/default_user_avatar.png" class="img"></image>
|
||
</view>
|
||
<view class="msg_content">
|
||
<view class="title_div">
|
||
<view class="name">{{ childrenItem.userName }}</view>
|
||
<view class="arrow"></view>
|
||
<view class="name">{{ childrenItem.rtnUName }}</view>
|
||
</view>
|
||
<view class="title">
|
||
{{ childrenItem.bbsContent }}
|
||
</view>
|
||
<view class="img_div"></view>
|
||
<view class="time_and_reply">
|
||
<view class="time">{{ childrenItem.bbsTm.substr(0, 16) }}</view>
|
||
<view class="reply" @click="click_reply(childrenItem, childrenItem.parentId, index)">
|
||
回复
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="empty_message_div" v-if="status == 'nomore' && total == 0">
|
||
<image class="img" src="@/static/images/courseDetail/empty_message.png" mode="widthFix"></image>
|
||
<view class="text">这里什么都没有</view>
|
||
</view>
|
||
<uv-load-more v-if="total != 0" :status="status" loadmore-text="轻轻上拉加载"></uv-load-more>
|
||
<uni-popup ref="popup" class="popup">
|
||
<view class="bottom_reply_input_div" :style="{ marginBottom: popup_input_bottom }">
|
||
<uv-input
|
||
v-model="reply_data.bbsContent"
|
||
:adjustPosition="false"
|
||
placeholderStyle="color:#999999;font-size:26rpx"
|
||
:placeholder="reply_data.placeholder"
|
||
:focus="true"
|
||
:maxlength="100"
|
||
></uv-input>
|
||
<view class="" style="display: flex; flex-direction: column; margin: 10rpx 20rpx">
|
||
<view class="fl1"></view>
|
||
<uv-button class="bottom_reply_button" type="primary" :throttleTime="500" @click="reply_send">
|
||
回复
|
||
</uv-button>
|
||
<view class="fl1"></view>
|
||
</view>
|
||
</view>
|
||
</uni-popup>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, onMounted, nextTick } from 'vue';
|
||
import { queryTraCrsBbsInfoByCrsId, replyTraCrsBbsInfo, qryChildTraCrsBbsInfo } from '@/api/courseDetail.js';
|
||
import common from '@/common/common.js';
|
||
import { get_base_url } from '@/api/request.js';
|
||
|
||
const popup = ref(null);
|
||
const popup_input_bottom = ref('0px');
|
||
|
||
const inputValue = ref('');
|
||
const placeholder = ref('');
|
||
const message_list = reactive([]);
|
||
const status = ref(''); // loadmore - 加载前,loading - 加载中,nomore - 没有数据
|
||
const limit = 20;
|
||
const total = ref(-1);
|
||
const page = ref(0);
|
||
const reply_data_init = {
|
||
index: null,
|
||
parentBbsId: null,
|
||
bbsId: null,
|
||
bbsContent: '',
|
||
placeholder: ''
|
||
};
|
||
const reply_data = reactive({
|
||
...reply_data_init
|
||
});
|
||
|
||
const props = defineProps({
|
||
crsId: String,
|
||
imgId: String
|
||
});
|
||
const click_reply = (item, parentBbsId, index) => {
|
||
popup.value.open('bottom');
|
||
reply_data.placeholder = '回复 ' + item.userName + ':';
|
||
reply_data.parentBbsId = parentBbsId;
|
||
reply_data.bbsId = item.bbsId;
|
||
reply_data.index = index;
|
||
const systemInfo = uni.getSystemInfoSync();
|
||
// 安全区域底部到屏幕底部的高度(即底部安全区域高度)
|
||
const safeAreaBottomHeight = systemInfo.screenHeight - systemInfo.safeArea.bottom;
|
||
nextTick(() => {
|
||
uni.onKeyboardHeightChange((res) => {
|
||
let keyboardHeight = res.height;
|
||
// 仅在iOS端补偿安全区域高度
|
||
if (systemInfo.platform === 'ios') {
|
||
keyboardHeight = Math.max(0, keyboardHeight - safeAreaBottomHeight); // 避免负数
|
||
}
|
||
popup_input_bottom.value = `${keyboardHeight}px`;
|
||
});
|
||
});
|
||
};
|
||
const reply_send = async () => {
|
||
if (reply_data.bbsContent === '') {
|
||
return common.msg('回复内容不能为空');
|
||
}
|
||
try {
|
||
popup.value.close();
|
||
common.loading('发送中...');
|
||
await replyTraCrsBbsInfo({
|
||
parentBbsId: reply_data.parentBbsId,
|
||
bbsId: reply_data.bbsId,
|
||
bbsContent: reply_data.bbsContent,
|
||
imgIdList: []
|
||
});
|
||
common.msg('发送成功');
|
||
const res = await qryChildTraCrsBbsInfo({
|
||
bbsId: reply_data.parentBbsId
|
||
});
|
||
message_list[reply_data.index]['children'] = res.body;
|
||
Object.assign(reply_data, reply_data_init);
|
||
} catch (e) {
|
||
common.msg('发送失败');
|
||
} finally {
|
||
common.hideLoading();
|
||
}
|
||
};
|
||
|
||
const getData = (from = '') => {
|
||
if (from == 'submit') {
|
||
status.value = '';
|
||
total.value = -1;
|
||
page.value = 1;
|
||
message_list.length = 0;
|
||
} else {
|
||
if (status.value !== 'loadmore' && status.value !== '') return;
|
||
status.value = 'loading';
|
||
page.value++;
|
||
}
|
||
|
||
queryTraCrsBbsInfoByCrsId({
|
||
crsId: props.crsId,
|
||
page: page.value,
|
||
limit: limit
|
||
})
|
||
.then((res) => {
|
||
total.value = res.total;
|
||
message_list.push(...res.body);
|
||
})
|
||
.finally(() => {
|
||
if (message_list.length >= total.value) {
|
||
status.value = 'nomore';
|
||
} else {
|
||
status.value = 'loadmore';
|
||
}
|
||
});
|
||
};
|
||
|
||
// 大图展示
|
||
const showPicture = (urls, item) => {
|
||
const base_url = get_base_url();
|
||
const current = urls.findIndex((res) => item === res);
|
||
if (current === -1) {
|
||
return false;
|
||
}
|
||
const urlsList = urls.map((res) => base_url + res);
|
||
console.log(urlsList, current);
|
||
uni.previewImage({
|
||
current: current || 0,
|
||
urls: urlsList,
|
||
longPressActions: {
|
||
// itemList: ['发送给朋友', '保存图片', '收藏'],
|
||
itemList: ['保存图片'],
|
||
success: function (data) {
|
||
uni.saveImageToPhotosAlbum({
|
||
filePath: urlsList[data.index],
|
||
success: function () {}
|
||
});
|
||
},
|
||
fail: function (err) {}
|
||
}
|
||
});
|
||
};
|
||
defineExpose({
|
||
getData
|
||
});
|
||
onMounted(() => {
|
||
getData();
|
||
});
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.popup {
|
||
z-index: 18000;
|
||
}
|
||
|
||
.empty_message_div {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
padding: 80rpx 0;
|
||
flex-direction: column;
|
||
.img {
|
||
width: 20vw;
|
||
// height: 276rpx;
|
||
}
|
||
.text {
|
||
margin-top: 24rpx;
|
||
font-weight: 400;
|
||
font-size: 29rpx;
|
||
color: #999999;
|
||
text-align: center;
|
||
font-style: normal;
|
||
}
|
||
}
|
||
|
||
.pic-cell {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.pic-item {
|
||
margin-right: 16rpx;
|
||
width: 170rpx;
|
||
height: 170rpx;
|
||
border-radius: 8rpx;
|
||
// background-color: red;
|
||
margin-bottom: 24rpx;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.send_evaluate_div_height {
|
||
height: 170rpx;
|
||
}
|
||
|
||
.send_evaluate_div {
|
||
position: fixed;
|
||
left: 0;
|
||
bottom: 0;
|
||
width: 100%;
|
||
padding: 10rpx 20rpx 30rpx 20rpx;
|
||
// padding-top: 10rpx;
|
||
// padding-bottom: 30rpx;
|
||
background-color: #ffffff;
|
||
|
||
// background-color: red;
|
||
:deep(.uv-button-wrapper) {
|
||
.uv-button {
|
||
border-radius: 14rpx;
|
||
height: 92rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 顶部随着输入法弹出的框
|
||
.bottom_reply_input_div {
|
||
width: 100%;
|
||
height: 100%;
|
||
background-color: #ffffff;
|
||
display: flex;
|
||
bottom: 40vh;
|
||
align-items: center;
|
||
padding: 10rpx 10rpx;
|
||
|
||
.bottom_reply_button {
|
||
border: none;
|
||
border-radius: 4rpx;
|
||
background-color: #0066ff;
|
||
color: #ffffff;
|
||
overflow: hidden;
|
||
|
||
:deep(.uv-button) {
|
||
height: 60rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.back_div {
|
||
margin-left: 6rpx;
|
||
|
||
.back-icon {
|
||
position: relative;
|
||
width: 26rpx;
|
||
height: 26rpx;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.back-icon::before,
|
||
.back-icon::after {
|
||
content: '';
|
||
position: absolute;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.back-icon::after {
|
||
top: 2%;
|
||
left: 25%;
|
||
width: 50%;
|
||
height: 50%;
|
||
border-top: 3rpx solid #0066ff;
|
||
border-left: 3rpx solid #0066ff;
|
||
transform: rotate(-135deg);
|
||
}
|
||
}
|
||
|
||
.message_div:not(:first-child) {
|
||
margin-top: 30rpx;
|
||
}
|
||
|
||
.message_div {
|
||
// margin-top: 30rpx;
|
||
display: flex;
|
||
margin-left: 20rpx;
|
||
margin-right: 20rpx;
|
||
|
||
.head_div {
|
||
.img {
|
||
border-radius: 100%;
|
||
width: 78rpx;
|
||
height: 78rpx;
|
||
overflow: hidden;
|
||
}
|
||
}
|
||
|
||
.msg_content {
|
||
margin-left: 22rpx;
|
||
flex: 1;
|
||
overflow: hidden;
|
||
|
||
.title_div {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.name {
|
||
height: 35rpx;
|
||
font-family: PingFangSC, PingFang SC;
|
||
font-weight: 400;
|
||
font-size: 25rpx;
|
||
color: #666666;
|
||
line-height: 35rpx;
|
||
text-align: left;
|
||
font-style: normal;
|
||
}
|
||
|
||
.title_tip {
|
||
margin-left: 16rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
.img {
|
||
width: 92rpx;
|
||
}
|
||
}
|
||
|
||
.arrow {
|
||
margin: 0 12rpx 0 14rpx;
|
||
position: relative;
|
||
width: 12rpx;
|
||
height: 20rpx;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.arrow::after {
|
||
content: '';
|
||
position: absolute;
|
||
background-color: #666666;
|
||
right: 4rpx;
|
||
width: 18rpx;
|
||
height: 12rpx;
|
||
transform: rotate(45deg);
|
||
}
|
||
}
|
||
|
||
.title {
|
||
margin: 4rpx 0;
|
||
font-family: PingFangSC, PingFang SC;
|
||
font-weight: 400;
|
||
font-size: 30rpx;
|
||
color: #333333;
|
||
text-align: left;
|
||
line-height: 48rpx;
|
||
text-overflow: ellipsis;
|
||
white-space: wrap;
|
||
overflow-wrap: anywhere;
|
||
}
|
||
|
||
.time_and_reply {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 28rpx;
|
||
|
||
.time {
|
||
font-family: ArialMT;
|
||
font-size: 24rpx;
|
||
color: #666666;
|
||
line-height: 27rpx;
|
||
text-align: left;
|
||
font-style: normal;
|
||
}
|
||
|
||
.reply {
|
||
margin-left: 16rpx;
|
||
font-family: PingFangSC, PingFang SC;
|
||
font-weight: 400;
|
||
font-size: 24rpx;
|
||
color: #0066ff;
|
||
line-height: 33rpx;
|
||
text-align: left;
|
||
font-style: normal;
|
||
}
|
||
}
|
||
|
||
.show_close_div {
|
||
margin-top: 12rpx;
|
||
margin-bottom: 20rpx;
|
||
font-family: PingFangSC, PingFang SC;
|
||
font-weight: 400;
|
||
font-size: 24rpx;
|
||
color: #0066ff;
|
||
line-height: 30rpx;
|
||
text-align: left;
|
||
font-style: normal;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
}
|
||
}
|
||
|
||
.comment_scroll {
|
||
height: calc(100vh - 92rpx - 22rpx - 187rpx);
|
||
}
|
||
|
||
.comment_div {
|
||
padding: 20rpx 0 20rpx 0;
|
||
background-color: #ffffff;
|
||
border-radius: 24rpx;
|
||
position: relative;
|
||
|
||
// height: calc(100vh - 88rpx - 162rpx - 256rpx - 70rpx);
|
||
// overflow: hidden;
|
||
}
|
||
</style>
|