Files
xdd-uniapp-new/pagesInn/inn/innInfoDetail.vue
T

933 lines
21 KiB
Vue

<template>
<view class="info-section">
<view class="info-item">
<view
:class="item.isTop === 1 ? 'info-item-top' : ''"
:style="{
'background-image': item.isTop
? 'url(' + webUrl + '/page/hotel/info-top-bg.png)'
: 'none',
}"
class="info-item-header"
>
<view class="name">
{{ item.name }}
</view>
<view class="intro">
{{ item.intro }}
</view>
</view>
<view class="info-item-body">
<view v-if="item.type === 'NT_VIDEO'" class="video">
<video
:src="item.video"
:poster="item.video + '?vframe/jpg/offset/1'"
controls
play-btn-position="center"
class="video-item"
:id="'video-item' + index"
/>
</view>
<view v-else>
<img-box
v-if="item.resources"
:imgList="item.resources"
:num="item.resources.length"
:img-radius="10"
style="width: 100%"
/>
</view>
</view>
<view class="info-item-bottom">
<view class="time">
{{
item.publishTime
? item.publishTime.replace(/-/g, ".").substr(0, 10)
: ""
}}
</view>
<view class="btns">
<view class="flex">
<image :src="webUrl + '/20230803152147141807.png'" class="icon" />
<text class="seeNum-txt">{{ item.pv }}</text>
</view>
<view class="flex">
<image
v-if="!item.zanVo"
:src="webUrl + '/page/hotel/zan-off-2.png'"
class="zan-off-icon"
@click="likeInfo"
/>
<image
v-else
:src="webUrl + '/page/hotel/zan-on-2.png'"
class="zan-on-icon"
@click="likeInfo"
/>
<text
v-show="item.zan > 0"
:class="item.zanVo ? 'on' : ''"
class="seeNum-txt"
>{{ item.zan }}</text
>
</view>
<view class="flex">
<u-icon name="chat" size="24"></u-icon>
<text class="seeNum-txt">{{ item.replyCount || comments.length }}</text>
</view>
</view>
</view>
</view>
<view class="v12-px-2">资讯评论</view>
<view v-if="comments.length === 0" class="v12-text-center v12-py-2 v12-dark1-text v12-font-24">
暂无评论
</view>
<view class="comment-list">
<view class="v12-mt-2" v-for="(comment, index) in comments" :key="index" @click="selectComment(comment)">
<view class="user-info v12-align-center">
<view class="user-avatar">
<u-avatar :src="comment.userAvatar"></u-avatar>
</view>
<view class="user-name v12-ml-3">
<view class="v12-font-bold v12-dark-text v12-font-32">
<text>{{ comment.userNickName }}</text>
<text v-if="comment.userIsAdmin" class="v12-ml-1 v12-primary v12-white-text v12-font-24 v12-font-weight-400 v12-px-1 v12-radius-8">
{{ '店主' }}
</text>
</view>
<view class="v12-font-22 v12-secondary-dark-text v12-mt-1">
<text>{{ formatterTime(comment.createTime) }}</text>
<text v-if="comment.at">
{{ ' 回复 ' + comment.at.atNickName }}
</text>
</view>
</view>
</view>
<view class="user-info v12-d-flex" >
<view class="user-avatar">
<view style="opacity: 0;">
<u-avatar></u-avatar>
</view>
</view>
<view class="user-name v12-ml-3">
<view class="v12-font-28 v12-dark-text">
{{ comment.reply }}
</view>
<view v-if="comment.children">
<view class="v12-mt-2" v-for="(_comment, atIndex) in comment.children" :key="atIndex" @click.stop="selectComment(_comment)">
<view class="user-info v12-align-center">
<view class="user-avatar">
<u-avatar size="35" :src="_comment.userAvatar"></u-avatar>
</view>
<view class="user-name v12-ml-3">
<view class="v12-font-bold v12-dark-text v12-font-32">
<text>{{ _comment.userNickName }}</text>
<text v-if="_comment.userIsAdmin" class="v12-ml-1 v12-primary v12-white-text v12-font-24 v12-font-weight-400 v12-px-1 v12-radius-8">
{{ '店主' }}
</text>
</view>
<view class="v12-font-22 v12-secondary-dark-text v12-mt-1">
<text>{{ formatterTime(_comment.createTime) }}</text>
<text v-if="_comment.at && _comment.parentReplyId !== comment.id">
{{ ' 回复 ' + _comment.at.atNickName }}
</text>
</view>
</view>
</view>
<view class="user-info v12-align-center">
<view class="user-avatar">
<view style="opacity: 0;">
<u-avatar size="35"></u-avatar>
</view>
</view>
<view class="user-name v12-ml-3">
<view class="v12-font-28 v12-dark-text">
<text class="v12-dark1-text">{{ _comment.reply.split(' ')[0] }}</text>
{{ ' ' + _comment.reply.split(' ')[1] }}
</view>
</view>
</view>
</view>
<view v-if="comment.hasMoreChildren" class="more-text" @click.stop="showMoreComment(comment)">
{{ '—— 点击展开更多回复 ——' }}
</view>
</view>
</view>
</view>
</view>
</view>
<view class="comment-input-wrap">
<view style="width: 100%;">
<u-textarea
@focus="commentInputFocus"
@change="commentInputChange"
:prefixIcon="prefixIcon"
class="comment-input"
:showConfirmBar="false"
cursorSpacing="15"
v-model="reply"
autoHeight
placeholder="分享你的观点,让世界听见你的声音...">
<template slot="prefix">
<view class="v12-align-center">
<u-icon :name="prefixIcon"></u-icon>
<u--text
v-if="currentComment.userNickName"
:text="'@' + currentComment.userNickName"
margin="0 3px 0 0"
type="tips"
></u--text>
</view>
</template>
</u-textarea>
</view>
<view class="">
<view class="send-btn v12-primary v12-white-text" @click="sendComment">发送</view>
</view>
</view>
</view>
</template>
<script>
import { getHotelNewsDetail, getHotelNewsZan, getCommentList, addComment } from "@/api/inn";
import imgBox from '@/components/imageTypeSet/imagebox.vue'
export default {
components: {
imgBox
},
data() {
return {
webUrl: this.$VUE_APP_RESOURCES_URL,
id: null,
item: {},
comments: [],
reply: '',
atUid: '',
currentComment: {},
prefixIcon: 'edit-pen'
};
},
onLoad(options) {
this.id = options.id;
this.init();
},
methods: {
showMoreComment(comment) {
const params = {
contentId: this.id,
contentType: "hotelNews",
rootReplyId: comment.id,
page: 1,
limit: 99999,
}
uni.showLoading({
mask: true,
});
getCommentList(params).then((res) => {
uni.hideLoading();
comment.children = res.data.records
comment.hasMoreChildren = false
})
},
commentInputChange(e) {
// 若删除直接将@用户名整个删除
if (e === '') {
this.currentComment = {}
return
}
// 若删除@用户名,将@用户名整个删除
const usernameLength = `@${this.currentComment.userNickName}`.length
if(!e.includes(`@${this.currentComment.userNickName}`) && this.currentComment.userNickName) {
this.currentComment = {}
this.reply = e.slice(usernameLength - 1); // 去除@用户名
}
},
commentInputFocus(e) {
// this.prefixIcon = ''
},
selectComment(comment) {
this.currentComment = comment;
// this.prefixIcon = ''
this.reply = '@' + comment.userNickName + ' '
},
/**
* 格式化时间
* @param {*} time 时间
* @returns 距离当前时间的时间差
* 1. 小于1分钟,显示刚刚
* 2. 小于1小时,显示xx分钟前
* 3. 小于1天,显示xx小时前
* 4. 超过7天,显示日期 xxxx年xx月xx日
*/
formatterTime(time) {
const now = new Date();
const date = new Date(time);
const diff = now - date;
const diffMin = Math.floor(diff / 1000 / 60);
const diffHour = Math.floor(diff / 1000 / 60 / 60);
const diffDay = Math.floor(diff / 1000 / 60 / 60 / 24);
if (diffMin < 1) {
return "刚刚";
} else if (diffHour < 1) {
return diffMin + "分钟前";
} else if (diffDay < 1) {
return diffHour + "小时前";
} else if (diffDay < 7) {
return diffDay + "天前";
} else {
return date.getFullYear() + "年" + (date.getMonth() + 1) + "月" + date.getDate() + "日";
}
},
/**
* 发评论
*/
sendComment() {
if (!this.reply.trim()) {
uni.showToast({
title: '请输入评论内容',
icon: 'none'
})
return
}
uni.showLoading({
mask: true,
});
const params = {
contentId: this.id,
contentType: 'hotelNews',
parentReplyId: this.currentComment.parentId || this.currentComment.id,
reply: this.reply,
atUid: this.currentComment.uid || null,
}
addComment(params).then((res) => {
console.log(res);
uni.hideLoading();
this.init()
this.reply = ''
this.currentComment = {}
this.item.replyCount === null ? this.item.replyCount = 1 : this.item.replyCount++
})
},
init() {
getHotelNewsDetail(this.id).then(({ data }) => (this.item = data));
this.getComment();
},
// contentId int 评论的目标内容ID,必传
// contentType string 评论的目标内容类型,必传(店铺资讯传入值hotelNews)
// rootReplyId int 根评论ID
// page int 页码
// limit int 每页数量
getComment() {
const params = {
contentId: this.id,
contentType: "hotelNews",
page: 1,
limit: 99999,
}
getCommentList(params).then((res) => {
console.log(res);
this.comments = res.data.records
})
},
likeInfo() {
uni.showLoading({
mask: true,
});
getHotelNewsZan(this.id)
.then((res) => {
uni.hideLoading();
getHotelNewsDetail(this.id).then(({ data }) => (this.item = data));
})
.catch((err) => {
uni.hideLoading();
});
},
},
};
</script>
<style lang="less">
@import "@/assets/css/store.less";
.comment-list{
padding-bottom: 100rpx;
}
.more-text{
color:#1B76F0;
font-weight: 400;
font-size: 28rpx;
}
.comment-input-wrap{
padding: 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
position: -webkit-sticky;
position: fixed;
width: 100%;
box-sizing: border-box;
bottom: 0;
background: #fff;
left: 0;
}
.comment-input{
height: 70rpx;
background: rgba(246,246,246,0.39);
border-radius: 12rpx;
}
.send-btn{
border-radius: 16rpx;
width: 96rpx;
height: 70rpx;
line-height: 70rpx;
text-align: center;
margin-left: 30rpx;
}
.my-inn-page {
padding: 0 0 100rpx 0;
background-color: #f6f6f6;
}
.cover-box {
position: relative;
.full-img {
width: 750rpx;
}
.video {
display: block;
width: 100%;
height: 100%;
}
}
.guarantee {
margin-right: 16rpx;
padding: 8rpx 16rpx;
border-radius: 8rpx;
background: #0DC5C5;
color: #fff;
font-size: 22rpx;
line-height: 1;
}
.zan-favorite-wrap {
font-size: 32rpx;
color: #333;
.on {
color: #FF564A;
}
}
.zan-box {
.img {
width: 36rpx;
height: 36rpx;
margin: 0 8rpx 0 0;
vertical-align: middle;
}
}
.favorite-box {
.icon {
width: 36rpx;
height: 36rpx;
margin: 0 8rpx 0 30rpx;
}
}
.store-img {
width: 686rpx;
margin-bottom: 20rpx;
vertical-align: middle;
}
.goods-section {
padding: 40rpx 32rpx 0;
background: #F5F5FA;
.item {
position: relative;
width: 332rpx;
height: 528rpx;
box-sizing: border-box;
margin-right: 22rpx;
margin-bottom: 24rpx;
border-radius: 8rpx;
background: #fff;
.name {
padding: 0 6rpx;
font-size: 26rpx;
color: #333333;
}
.price-line {
padding: 0 10rpx;
font-size: 26rpx;
line-height: 38rpx;
color: #ED0F0F;
}
.sales-line {
position: absolute;
bottom: 0;
width: 100%;
padding: 8rpx 10rpx 18rpx;
border-top: 1rpx solid #EFEFEF;
font-size: 24rpx;
line-height: 34rpx;
color: #8D8D8D;
}
}
.item:nth-child(2n) {
margin-right: 0;
}
.cover {
width: 332rpx;
height: 332rpx;
background: rgba(255, 255, 255, 0.39);
border-radius: 8rpx;
vertical-align: middle;
}
.label {
width: 40rpx;
height: 24rpx;
margin-right: 4rpx;
vertical-align: middle;
}
.icon {
width: 24rpx;
height: 24rpx;
margin-right: 6rpx;
vertical-align: middle;
}
.btn {
display: flex;
padding: 20rpx 0 40rpx 0;
justify-content: center;
.btn-cont {
padding: 13rpx 30rpx;
border: 1px solid #0DC5C5;
border-radius: 8rpx;
color: #0DC5C5;
.iconfont {
margin: 0 0 0 20rpx;
font-size: 24rpx;
}
}
}
}
.container {
position: relative;
background: #FFFFFF;
}
.innInfoWrap {
position: relative;
margin-top: -76rpx;
padding: 20rpx 36rpx;
line-height: 1;
z-index: 1;
.bg-color {
position: absolute;
top: -5px;
left: 0;
right: 0;
z-index: 1;
height: 50%;
background: linear-gradient(-180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 100%);
.box-mask {
position: absolute;
bottom: 0;
right: 0;
left: 166rpx;
box-sizing: border-box;
padding: 0 32rpx 12rpx 0;
.city-section {
width: 256rpx;
margin-left: 20rpx;
}
}
}
.body-cont {
position: relative;
z-index: 2;
}
}
.inn-logo {
flex-shrink: 0;
width: 56*2rpx;
height: 56*2rpx;
margin-right: 18rpx;
}
.inn-logo image {
width: 100%;
height: 100%;
border-radius: 50%;
}
.inn-name {
width: 280rpx;
font-size: 32rpx;
color: #FFFFFF;
line-height: 48rpx;
}
.inn-owner {
font-size: 24rpx;
color: #8B8F99;
}
.inn-tag-wrap {
margin-top: 10rpx;
}
.inn-signature-wrap {
position: relative;
z-index: 5;
padding: 0 32rpx;
margin: 20rpx 0 0 0;
.triangle {
position: absolute;
top: -20rpx;
left: 72rpx;
width: 0;
height: 0;
border-left: 20rpx solid transparent;
border-right: 20rpx solid transparent;
border-bottom: 24rpx solid rgba(243,243,246,0.39);
}
.inn-signature {
position: relative;
padding: 20rpx;
border-radius: 8rpx;
font-size: 24rpx;
color: #080F1A;
background: rgba(243,243,246,0.39);
box-shadow: 0px 6px 12px rgba(0,0,0,0.12);
}
.share-btn {
position: absolute;
right: 0;
bottom: -68rpx;
.img {
width: 212rpx;
height: 60rpx;
}
}
}
.btLine {
width: 100%;
height: 6rpx;
margin-top: 18rpx;
background: #0DC5C5;
}
.pics-box {
margin: 36rpx;
background: #fff;
}
.pics-list {
position: relative;
padding: 32rpx 0;
flex-wrap: wrap;
}
.pics-list .pics-item {
margin-left: 36rpx;
margin-top: 20rpx;
}
.bottom-view {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 99;
display: flex;
height: 70rpx;
padding: 15rpx;
border-top: 1px solid #f1f1f1;
background: #FFFFFF;
.bottom-btn {
display: flex;
flex: 1;
align-items: center;
justify-content: center;
font-size: 32rpx;
color: #333;
line-height: 70rpx;
&:first-child {
border-right: 1px solid #d5d5d5;
}
.img {
width: 40rpx;
height: 40rpx;
margin: 0 12rpx 0 0;
}
}
}
.tab-item-active {
color:#080F1A;
font-size:32rpx;
}
.tab-item-no-active {
color:#A6AAB3;
font-size:28rpx;
}
.map-wrapper {
position: relative;
z-index: 2;
height: 200rpx;
margin: 40rpx 0 0 0;
overflow: hidden;
.map-cont {
position: absolute;
top: 0;
left: 0;
z-index: 2;
width: 100%;
opacity: 0.3;
transform: translateY(-50rpx);
}
.bg {
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 3;
height: 60rpx;
background: linear-gradient(180deg, #FFFFFF 0%, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%);
}
.map-info {
position: relative;
z-index: 5;
display: flex;
align-items: center;
padding: 40rpx 10rpx 40rpx 32rpx;
color: #333;
font-size: 14px;
justify-content: space-between;
.map-info-hd {
.icon {
display: block;
width: 56rpx;
height: 56rpx;
}
}
.map-info-bd {
flex: 1;
padding: 0 60rpx 0 20rpx;
line-height: 60rpx;
}
.map-info-ft {
.item + .item {
margin: 0 0 0 6rpx;
}
.item {
text-align: center;
font-weight: 500;
.img {
display: block;
width: 96rpx;
height: 96rpx;
margin: 0 0 -16rpx 0;
}
}
}
}
}
.top-tab {
margin: 60rpx 0 0 0;
border-bottom: 1px solid #ddd;
.tab {
margin: 0 35rpx;
&.hide {
display: none;
}
}
}
.info-section,
.pics-section,
.qualifications-section {
position: relative;
background-color: #fff;
}
.info-section,
.qualifications-section {
padding: 32rpx;
}
.info-section {
word-break: break-all;
min-height: 100vh;
.info-item + .info-item {
margin: 32rpx 0 0 0;
}
.info-item {
border-radius: 10rpx;
background-color: #fff;
.info-item-header {
position: relative;
padding: 20rpx 20rpx 0 20rpx;
&.info-item-top {
padding-top: 60rpx;
background-size: 100% 80rpx;
background-repeat: no-repeat;
background-image: url();
}
.name {
font-size: 16px;
color: #333;
font-weight: bold;
}
.intro {
margin: 10rpx 0 0 0;
color: #666;
font-size: 14px;
}
}
.info-item-body {
padding: 0 20rpx 20rpx 20rpx;
.video {
padding: 20rpx 0 0 0;
.video-item {
width: 100%;
height: 400rpx;
border-radius: 10rpx;
}
}
}
.info-item-bottom {
display: flex;
align-items: center;
padding: 0 20rpx 20rpx 20rpx;
margin-bottom: 20rpx;
border-bottom: 1px solid #f1f1f1;
font-size: 16px;
.time {
flex: 1;
color: #333;
}
.btns {
display: flex;
color: #999;
.flex + .flex {
margin: 0 0 0 32rpx;
}
.flex {
align-items: center;
}
.icon {
width: 32rpx;
height: 32rpx;
margin: 0 8rpx 0 0;
}
.zan-off-icon {
width: 40rpx;
height: 40rpx;
}
.zan-on-icon {
width: 40rpx;
height: 40rpx;
}
.seeNum-txt {
&.on {
color: #D81E06;
}
}
.more-btn {
position: relative;
.more-wrapper {
position: absolute;
right: -20rpx;
top: -150rpx;
z-index: 5;
width: 200rpx;
border-radius: 12rpx;
background-color: #fff;
box-shadow: 0px 1px 6px rgba(0,0,0,0.16);
.more-item + .more-item {
border-top: 1px solid #d5d5d5;
}
.more-item {
display: flex;
align-items: center;
justify-content: center;
height: 70rpx;
font-size: 14px;
color: #333;
.more-icon {
width: 36rpx;
height: 36rpx;
margin: 0 10rpx 0 0;
}
}
}
}
}
}
}
}
.tab-no-data {
text-align: center;
font-size: 32rpx;
color: #999;
line-height: 200rpx;
}
.pages-inn-info-detail {
.top-box {
padding: 40rpx 32rpx 20rpx;
box-shadow: 0 6rpx 12rpx rgba(0, 0, 0, 0.16);
.title {
margin-bottom: 20rpx;
font-size: 40rpx;
font-weight: bold;
line-height: 64rpx;
color: #333333;
}
.sub {
font-size: 32rpx;
line-height: 1;
color: #333333;
image {
width: 40rpx;
height: 40rpx;
margin-right: 4rpx;
vertical-align: middle;
}
.datetime {
color: #999999;
}
.num {
line-height: 40rpx;
}
}
}
.video-box {
box-sizing: border-box;
padding: 40rpx 32rpx 0;
}
.content-box {
padding: 40rpx 32rpx;
box-sizing: border-box;
}
}
.user-info{
view{
word-break: break-all;
}
}
</style>