This commit is contained in:
liuyuan
2025-06-12 14:26:50 +08:00
parent 9a2c26ace8
commit e415f34fa8
15 changed files with 735 additions and 3668 deletions

View File

@@ -1,839 +0,0 @@
<template>
<view class="container">
<view class="header">
<!-- 顶部导航栏 -->
<z-nav-bar :title="productInfo.name+'-书评'"></z-nav-bar>
</view>
<view class="bookInfo">
<!-- <image :src="productInfo.images" mode="aspectFill"></image>
<view>
<span class="title">{{productInfo.name}}</span>
<view class="description" v-if="productInfo.description == ''">暂无简介内容</view>
<view class="description">{{productInfo.description}}</view>
</view> -->
<view class="flexbox" style="margin-bottom: 20px;">
<image :src="productInfo.images" mode="aspectFill" class="imageradius bookinfoimage"></image>
<view class="bookInfo-inner">
<span class="title">{{productInfo.name}}</span>
<span class="author" v-if="productInfo.authorName!=''">作者{{productInfo.authorName}}</span>
<!-- <view class="description">{{productInfo.bookdesc}}</view> -->
<view class="ting-du-mai">
<view class="ting-du-mai-item" v-if="productInfo.canListen" @click="toOtherPage(1,productInfo)">
听书</view>
<view class="ting-du-mai-item" v-if="productInfo.clockIn == 1"
@click="toOtherPage(2,productInfo)">读书打卡</view>
<view class="ting-du-mai-item" v-if="productInfo.bookType == 0"
@click="toOtherPage(3,productInfo)">立即购买</view>
</view>
</view>
</view>
<view class="description" v-if="productInfo.content == ''">暂无简介内容</view>
<view class="description" v-else>简介{{productInfo.content}}</view>
</view>
<view class="mainContent">
<view v-if="shupingList.length > 0">
<view class="flexbox shuping-topbar">
<view class="shuping-topbar-tiao">{{shupingNum || 0}}条书评</view>
<view class="shuping-topbar-order">
<!-- <view v-for="(item,index) in orderTabs" @click="orderTabCLi(item.value)" :key="index"
:class="orderListTab==item.value?'orderdefine ordStyle':'orderdefine'">{{item.name}}</view> -->
<view :class="orderListTab==1?'orderdefine ordStyle':'orderdefine'" @click="orderTabCLi(1)">按时间
</view>
<view style="border-left:2rpx solid #e9e9e9;height:36rpx;"></view>
<view :class="orderListTab==2?'orderdefine ordStyle':'orderdefine'" @click="orderTabCLi(2)">按热度
</view>
</view>
</view>
<view class="item" @click.stop="toDetail(item)" v-for="(item,index1) in shupingList" :key="index1">
<view class="title">{{item.title}}</view>
<image class="feng" v-if="item.image" :src="item.image" mode="aspectFill"></image>
<view class="description descriptionNew" v-html="item.content">
</view>
<!-- <image class="feng" v-if="item.image == ''" src="../../static/icon/home_bg.jpg" mode="aspectFill"></image> -->
<view class="btns flexbox" style="margin-top:10rpx;">
<span class="left" style="color: #C0C4CC;">{{formatTimeDifferenceFromT(item.createTime)}}</span>
<span class="right flexbox opbtns">
<image class="gzicon" v-if="item.ilike" src="../../static/icon/gz2.png" mode="aspectFill"
@click.stop="clickLike(item)"></image>
<image class="gzicon" v-else src="../../static/icon/gz.png" mode="aspectFill"
@click.stop="clickLike(item)"></image>
<view style="color: #C0C4CC;">{{item.contlike}}</view>
<!-- <image class="gzicon" v-if="1" src="../../static/icon/pinglun.png" mode="aspectFill" @click.stop="pinglun(item.id)"></image>
<view style="color: #C0C4CC;" @click.stop="pinglun(item.id)">{{item.commentNum}}</view> -->
<image class="gzicon" v-if="1" src="../../static/icon/pinglun.png" mode="aspectFill">
</image>
<view style="color: #C0C4CC;">{{item.commentNum}}</view>
</span>
</view>
<view style="border-bottom:2rpx solid #e9e9e9;height:36rpx;" v-if="index1<shupingList.length-1">
</view>
<!-- <image class="feng" v-if="item.image == ''" src="../../static/icon/home_bg.jpg" mode="scaleToFill" style="width: 100%;"></image>
<image class="feng" v-else :src="item.image" mode="scaleToFill" style="width: 100%;"></image>
<text class="title">{{item.title}}</text> -->
<!-- <view class="description" v-html="item.content">
{{item.content}}
</view> -->
<!-- <view class="btns flexbox">
<span class="time">{{item.updateTime}}</span>
<span class="flexbox opbtns">
<span class="flexbox" @click="dianzan('1')">
<u-icon name="heart" color="#55aa00" size="26"></u-icon>
<text>2656</text>
</span>
<span class="flexbox pingjia" @click.stop="pinglun(item.id)">
<u-icon name="chat" color="#55aa00" size="26"></u-icon>
<text>2656</text>
</span>
</span>
</view> -->
</view>
</view>
<view class="quesheng" v-else>
暂无书评内容~
</view>
<view v-if="status==0" style="text-align: center;">
<u-loading-icon style="display: inline-block;"></u-loading-icon>
<font style='vertical-align: super;margin-left: 10px;font-size: 26rpx;color: #909399;'>努力加载中</font>
</view>
<view v-if="status==1" style="padding-bottom: 20rpx;">
<u-divider text="全部加载完成"></u-divider>
</view>
</view>
<!-- 评价对话框 -->
<u-popup :show="pingjiaShow" :round="10" @close="closePingjia">
<view class="tanchu">
<view class="dp_title">添加评论</view>
<view style="max-height: 1000rpx;overflow-y: scroll;">
<uni-forms :modelValue="Pform">
<!-- 评价图片 -->
<!-- end -->
<!-- <uni-forms-item name="comment" label-width="0">
<uni-easyinput type="textarea" v-model="Pform.comment" placeholder="请输入您的商品评价" />
</uni-forms-item> -->
</uni-forms>
<!-- <u-button type="success" @click="submitPJ">提交评价</u-button> -->
<!-- 提交 -->
<view class="padding-bottom-sm flex padding-lr-sm" style="border-bottom: 1px solid #EEEEEE;">
<view class="flex-sub flexbox">
<i @click="showEmj()" :class="emojiIcon"></i>
<!-- <input type="text" @focus="InputFocus" @blur="InputBlur" v-model="message" @input="textareaBInput" placeholder-style="font-size:24rpx;color:#aaaaaa;" placeholder="请输入您要发送的内容"></input> -->
<textarea class="textarea" v-model="Pform.comment" @focus="InputFocus" @blur="InputBlur"
@input="textareaBInput" placeholder-style="font-size:24rpx;color:#aaaaaa;"
placeholder="请输入您要发送的内容"></textarea>
</view>
<view class="">
<u-button type="success" @click="submitPJ">提交</u-button>
</view>
</view>
<view style="position: relative;">
<emotion @emotion="handleEmj" :height="220" v-if="isShowEmj" :windowWidth="windowWidth">
</emotion>
</view>
</view>
</view>
</u-popup>
<music-play :playData="playData"></music-play>
</view>
</template>
<script>
import $http from '@/config/requestConfig.js';
import emotion from '@/bkhumor-emojiplus/components/bkhumor-emojiplus/bkhumor-emojiplus.vue';
import musicPlay from '@/components/music.vue'
import {
data
} from 'jquery';
import {
mapState
} from 'vuex';
import {
checkBookRight
} from '@/config/utils';
export default {
data() {
return {
orderListTab: 1,
orderTabs: [{
name: '按时间',
value: 1
}, {
name: '按热度',
value: 2
}],
shupingNum: 0,
loadingNow: false,
playData: {},
isShowEmj: false,
emojiIcon: 'cuIcon-emoji',
windowWidth: 0,
bookid: null,
productInfo: {},
pingjiaShow: false, //添加评价
Pform: { // 评价表单
star: 0,
comment: '',
img: [],
html: ''
},
emoji: [],
Files: [],
page: 1,
pageSize: 10,
total: 0,
status: 3,
shupingList: [],
bfaid: null,
newTime:'',
}
},
onPullDownRefresh() {
console.log('下拉刷新了')
uni.stopPullDownRefresh();
this.page = 1, // 页码
this.shupingList = []
this.getBookCom(this.orderListTab)
},
onReachBottom() {
this.loadingNow = true
if (this.page < this.total) {
this.page++
console.log('加载', this.page)
this.status = 0
this.getBookCom(this.orderListTab)
} else {
this.status = 1
console.log('加载完成了', this.page)
return
}
},
onLoad(e) {
this.windowWidth = uni.getSystemInfoSync().windowWidth;
console.log(e, 'onload')
this.bookid = e.bookid
this.getProDetail(e)
this.getBookCom(this.orderListTab)
},
computed: {
...mapState(['userInfo']),
},
methods: {
toOtherPage(e, productInfo) {
if (e == 1) {
// 跳转到听书
uni.navigateTo({
url: "../listen/listen?bookid=" + productInfo.id
});
}
if (e == 2) {
// 跳转到读书打卡
let data = {
'userId': this.userInfo.id,
'bookId': productInfo.id
}
checkBookRight(data, res => {
console.log(res)
if (res.success) {
uni.navigateTo({
url: '../clock/clock?bookid=' + productInfo.id
})
} else {
uni.showToast({
title: '购买本书后方可参与打卡!',
icon: 'none'
})
}
})
}
if (e == 3) {
// 跳转到购买
uni.navigateTo({
url: '../bookShop/commodityDetail?id=' + productInfo.id
});
}
},
// 切换tab状态
orderTabCLi(e) {
this.orderListTab = e
this.page = 1
this.shupingList = []
this.getBookCom(this.orderListTab)
},
clickLike(item) {
this.$http
.post("forum/articles/chickForumContlike?forum_id=" + item.id, )
.then(res => {
if (res.code == 0) {
uni.showToast({
title: '点赞成功!',
icon: 'success'
})
item.contlike++
}
}).catch((e) => {
console.log(e, 'e')
})
},
formatTimeDifferenceFromT(dateTimeT) {
dateTimeT= dateTimeT.replace(/-/g,"/")
console.log("🚀 ~ formatTimeDifferenceFromT ~ dateTimeT:", dateTimeT)
const now = new Date();
const t = new Date(dateTimeT);
console.log("🚀 ~ formatTimeDifferenceFromT ~ t:", t)
const differenceInSeconds = Math.floor((now - t) / 1000);
console.log("🚀 ~ formatTimeDifferenceFromT ~ differenceInSeconds:", differenceInSeconds)
if (differenceInSeconds <= 3600) {
const minutes = Math.floor(differenceInSeconds / 60);
return `${minutes} 分钟前`;
} else if (differenceInSeconds <= 86400) {
const hours = Math.floor(differenceInSeconds / 3600);
return `${hours} 小时前`;
} else if (differenceInSeconds <= 2592000) {
const days = Math.floor(differenceInSeconds / 86400);
return `${days} 天前`;
} else {
const currentYear = now.getFullYear();
const tYear = t.getFullYear();
if (currentYear === tYear) {
const month = t.getMonth() + 1;
const day = t.getDate();
return `${month < 10 ? '0' : ''}${month}-${day < 10 ? '0' : ''}${day}`;
} else {
const year = t.getFullYear();
const month = t.getMonth() + 1;
const day = t.getDate();
return `${year}-${month < 10 ? '0' : ''}${month}-${day < 10 ? '0' : ''}${day}`;
}
}
},
// 书评详情
toDetail(val) {
console.log(val, 'val')
uni.navigateTo({
url: './commentsDetail?bookid=' + this.bookid + '&bfa_id=' + val.id
})
},
getProDetail(e) {
// 获取商品详情
uni.showLoading({
title: '加载中'
});
//console.log(e.id,'e.id')
this.$http
.post('book/book/appinfo/' + this.bookid + '/' + this.userInfo.id)
.then(res => {
console.log(res, 'res')
this.productInfo = res.book
uni.hideLoading();
}).catch((e) => {
console.log(e, 'e')
})
},
// 获得书评
getBookCom(flag) {
let data = {
'page': this.page,
'limit': this.pageSize,
'bookId': this.bookid,
'order': flag
}
console.log(data, 'data')
this.$http
.post('forum/articles/getForumByBook', data)
.then(res => {
console.log(res, '获取成功')
this.total = res.page.pages
this.shupingNum = res.page.total
this.shupingList = this.shupingList.concat(res.page.records)
// console.log(res,'已购买')
this.status = 3
}).catch((e) => {
console.log(e, 'e')
})
},
// 获得输入的表情数组
handleEmj(i) {
console.log(i, 'i---------');
this.inputValue = i
// console.log(this.inputValue);
if (i.emotioni == '[em_98]') {
//匹配最后一个表情符号并删除11。
this.Pform.comment = this.Pform.comment.replace(/(\[[^\]]+\]|[\s\S])$/, '');
if (this.emoji.length > 0) {
this.emoji = this.emoji.slice(0, -1)
}
} else {
this.emoji.push({
'tag': i.emotion,
'name': i.emotioni
})
// console.log(this.emoji,'this.emoji')
this.Pform.comment += i.emotioni;
/// this.Pform.html += i.emotion
}
},
textareaBInput(e) {
console.log(e, 'e')
this.Pform.comment = e.detail.value
/// this.Pform.html = e.detail.value
},
showEmj() {
let bool = !this.isShowEmj;
if (bool) {
this.emojiIcon = 'cuIcon-keyboard';
} else {
this.emojiIcon = 'cuIcon-emoji';
}
this.isShowEmj = bool;
this.$emit('show')
},
InputBlur(e) {
},
InputFocus(e) {
this.isShowEmj = false;
this.emojiIcon = 'cuIcon-emoji';
this.$emit('foc')
},
// end
deleteImg(e) {
// var arr = this.Pform.img.slice(0,-1)
this.Pform.img.pop()
// console.log('删除文件',arr)
console.log(this.Pform)
},
getStar(i) {
this.Pform.star = i
},
select(e) {
console.log('选择文件:', e)
let arr = e.tempFiles.map(item => {
return {
'url': item.url,
'name': item.name
}
})
this.Pform.img = this.Pform.img.concat(...arr)
//this.Pform.img = arr
console.log(this.Pform, 'img')
},
upSuccess(e) {
console.log(e)
},
// 获取html格式的评论1
getHtmlComment() {
// 格式化html
var ss = this.Pform.comment
if (this.emoji.length > 0) {
for (var i = 0; i < this.emoji.length; i++) {
if (this.Pform.comment.indexOf(this.emoji[i].name) !== -1) {
//var re = new RegExp(this.emoji[0].name,"g"); //定义正则表达式
//第一个参数是要替换掉的内容,第二个参数"g"表示替换全部global
// ss = ss.replace(re, ); //第一个参数是正则表达式。
ss = ss.replace(this.emoji[i].name, this.emoji[i].tag)
// console.log(ss)
}
}
this.Pform.html = ss
} else {
this.Pform.html = this.Pform.comment
}
//console.log(this.Pform.html,'this.Pform.html')
},
deletePic() {
let that = this
that.Pform.img.splice(0, 1)
//console.log(that.Pform.img)
},
afterRead(e) {
//console.log(e)
let that = this
for (var i = 0; i < e.file.length; i++) {
//console.log(i,e.file[i].url)
uni.uploadFile({
url: this.$baseUrl + 'oss/fileoss',
filePath: e.file[i].url,
//files:e.file,
name: 'file',
formData: {},
success: (res) => {
that.Pform.img.push({
url: JSON.parse(res.data).url
})
}
});
}
},
closePingjia() {
this.pingjiaShow = false
this.Pform.comment = ''
this.Pform.html = ''
this.emoji = []
},
// 点赞
dianzan(val) {},
// 显示评论
pinglun(val) {
this.bfaid = val
this.pingjiaShow = true
},
// 提交评论
submitPJ() {
if (this.Pform.comment != '') {
let data = {
'content': this.Pform.comment,
'userid': this.userInfo.id,
'bookid': this.bookid,
'bfaid': this.bfaid
}
// console.log(data,'data')
$http.request({
url: "forum/comment/save",
method: "POST", // POST、GET、PUT、DELETE具体说明查看官方文档
data,
header: { //默认 无 说明:请求头
'Content-Type': 'application/json'
},
}).then(res => {
if (res.code == 0) {
uni.showToast({
title: '评论成功!',
icon: 'success'
})
this.pingjiaShow = false
this.Pform.comment = ''
this.pinglunId = null
}
})
} else {
uni.showToast({
title: '请先输入您的评价内容 ',
icon: 'none'
})
}
},
},
components: {
musicPlay,
emotion
}
}
</script>
<style lang="scss" scoped>
.flexbox {
display: flex;
}
.container {
padding: 10px;
}
.star {
display: inline-block;
width: 20px;
height: 20px;
margin-right: 10rpx;
}
.starGray {
background: url(../../static/icon/star_greey.png) no-repeat;
background-size: contain;
}
.starLight {
background: url(../../static/icon/star_light.png) no-repeat;
background-size: contain;
}
.cuIcon-emoji {
background: url(../../static/biaoqing.png) no-repeat;
background-size: contain;
display: block;
margin-right: 20rpx;
width: 30px;
}
.cuIcon-keyboard {
background: url(../../static/biaoqing.png) no-repeat;
background-size: contain;
display: block;
width: 30px;
}
.tanchu {
padding: 40rpx 30rpx 40rpx 30rpx;
position: relative;
.dp_title {
font-size: 32rpx;
margin-bottom: 50rpx;
color: #555;
text-align: center;
font-weight: bold;
}
.dp_add {
position: absolute;
top: 40rpx;
right: 30rpx;
font-size: 22rpx;
background-color: #fd6004;
color: #fff;
border-radius: 10rpx;
padding: 5rpx 10rpx;
.u-icon {
display: inline-block;
margin-right: 5rpx;
}
}
}
.shuping-topbar {
display: flex;
justify-content: space-between;
align-items: center;
.shuping-topbar-tiao {
font-size: 28rpx;
color: #8b8a91;
}
.shuping-topbar-order {
width: 280rpx;
display: flex;
justify-content: space-between;
align-items: center;
.orderdefine {
display: inline-block;
padding: 20rpx 0 20rpx 0;
// margin: 40rpx 0 15rpx 0;
width: 230rpx;
text-align: center;
font-size: 30rpx;
}
.ordStyle {
// border-bottom: 4rpx solid #54a966;
// color: #54a966;
font-weight: bold;
}
}
}
.quesheng {
text-align: center;
margin-top: 100rpx;
color: #8b8a91;
padding-bottom: 20rpx;
padding-top: 20rpx;
}
.bookInfo {
justify-content: space-between;
margin-bottom: 15px;
background-color: #fff;
padding: 10px;
// border: 1px splid #999;
box-sizing: border-box;
padding-bottom: 20rpx;
border-radius: 20rpx;
margin-bottom: 20rpx;
.ting-du-mai {
display: flex;
justify-content: space-between;
align-content: center;
font-size: 28rpx;
width: 400rpx;
.ting-du-mai-item {
color: deepskyblue;
border: 1px solid deepskyblue;
border-radius: 6rpx;
padding: 4rpx 6rpx;
}
}
.imageradius {
border-radius: 20rpx;
border: 1rpx solid #e9e9e9;
}
.bookinfoimage {
width: 100px;
height: 100px;
}
.bookInfo-inner {
padding-left: 30rpx;
box-sizing: border-box;
width: calc(100% - 100px);
.title {
font-size: 32rpx;
margin-top: 0rpx;
margin-bottom: 20rpx;
font-weight: 700;
display: block;
}
.author {
font-size: 30rpx;
margin-top: 0rpx;
margin-bottom: 20rpx;
font-weight: 500;
display: block;
}
}
.description {
font-size: 28rpx;
line-height: 20px;
width: 100%;
color: #888;
padding-left: 0;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 9;
display: -webkit-box;
-webkit-box-orient: vertical;
}
// view{ padding-left: 30rpx; box-sizing: border-box; width: calc(100% - 150px);
// .title{font-size: 38rpx; margin-top: 20rpx; font-weight: blod; margin-bottom: 20rpx; display: block;
// }
// .description{line-height: 20px; width: 100%; color:#888; padding-left: 0;}
// }
// image{width: 150px !important; }
}
.mainContent {
background-color: #fff;
padding: 20rpx;
border-radius: 20rpx;
.item {
// padding: 10px;
margin-bottom: 30rpx;
// border: 1px solid #999;
box-sizing: border-box;
padding-bottom: 20rpx;
border-radius: 20rpx;
margin-bottom: 20rpx;
}
.feng {
margin: 10rpx 20rpx 0 0;
height: 160rpx;
width: 140rpx;
float: left;
border-radius: 20rpx;
border: 1rpx solid #e9e9e9;
}
.title {
font-size: 30rpx;
font-weight: 700;
color: #000;
overflow: hidden;
}
.description {
// width: 100%;
-webkit-box-orient: vertical;
overflow: hidden !important;
height:190rpx;
color: #666 !important;
text-overflow: -o-ellipsis-lastline !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
display: -webkit-box !important;
-webkit-line-clamp: 5 !important;
line-clamp: 5 !important;
-webkit-box-orient: vertical !important;
font-size: 26rpx !important;
margin-bottom: 20rpx !important;
margin-top: 10rpx !important;
white-space: pre-wrap;
// height: 172rpx;
}
// .btns{
// font-size: 24rpx;
// justify-content: space-between;
// align-items: center;
// .time{font-size: 24rpx; color: #666; }
// .opbtns{
// .pingjia{margin-left: 10px;}
// }
// }
.btns {
font-size: 22rpx;
justify-content: space-between;
align-items: center;
.left {
width: 300rpx;
color: #a1a1a1;
}
.right {
width: 300rpx;
display: flex;
justify-content: flex-end;
align-items: center;
}
.gzicon {
margin: 0 0 0 20rpx;
height: 40rpx;
width: 40rpx;
// float:left;
// border-radius: 20rpx;
// border:1rpx solid #e9e9e9;
}
.opbtns {
.pingjia {
margin-left: 10px;
}
}
}
}
.mb30 {
margin-bottom: 30rpx;
overflow: hidden;
}
.descriptionNew{
// overflow: auto;
}
</style>