Files
medicine_app/pages/peanut/bookshelf.vue
2024-05-22 13:42:15 +08:00

832 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view>
<!-- 公共组件-每个页面必须引入 -->
<public-module></public-module>
<z-nav-bar backState="2000" title="我的书架"></z-nav-bar>
<view v-if="this.bookData.length==0" style="margin-top: 250rpx;text-align: center;font-size: 30rpx;">暂无书籍</view>
<!-- 弹窗 -->
<view class="more-shade" v-if="moreOff" @click.stop="moreOff = false">
<view class="more">
<view class="more-list more-underline" @click.stop="examine">查看详情</view>
<view class="more-list more-underline remove" @click.stop="shiftOut">移出</view>
<view class="more-list" @click.stop="moreOff =false">取消</view>
</view>
</view>
<view class="bookrack-body" :class="{'bookrack-active' :checkboOff}">
<view class="book-top">
<view class="top-left" v-if="this.bookData.length!=0">
<view class="top-btn" v-if="!checkboOff" @click="managementBtn">
<view>管理</view>
</view>
<view class="top-btn" v-if="checkboOff" @click="accomplish">
完成
</view>
</view>
<!-- 搜索按钮 -->
<!-- <view class="top-right">
<view class="input-cancel" v-if="searchOff">
<view class="cancel-left">
<input class="uni-input" confirm-type="search" maxlength="50" placeholder="请输入关键词搜索" />
</view>
<view class="cancel-right">
<view class="top-btn" @click="cancelBtn">取消</view>
</view>
</view>
<view class="top-btn" v-if="!checkboOff && !searchOff" @click="searchBtn">
<span class="icon_search"></span>
</view>
</view> -->
</view>
<view class="book-rack">
<view style="text-align: right;font-size: 28rpx;margin: 20rpx;color: #5a5a5a;">{{bookData.length}}</view>
<view class="book-card" v-for="(item,index) in bookData" :key="index"
@click="bookCardBtn($event,index,'bookHeight' + index,item)" @longtap="managementBtn"
ref="bookcard">
<view class="book-checkbox" v-if="checkboOff">
<view class="checkboxcard" :class="{'checkboxactiva':item.checked}">
<view v-if="item.checked" class="check"></view>
</view>
</view>
<view class="image-text" :id="'bookHeight' + index">
<view class="ripple" v-if="index == bookNum" :style="{ top: leftY + 'px', left: topX + 'px' }">
</view>
<view class="book-left">
<image class="book-img" :src="item.image"></image>
</view>
<view class="book-right">
<view class="flex book-text">
<view class="head">{{item.bookName}}</view>
<view class="author">{{item.authorName}} []</view>
<view class="schedule">
<view class="schedule-text">已读 {{item.precent}}</view>
<view class="book-icon" v-if="!checkboOff">
<i class="iconfont omit" @click.stop="omitBtn(index,item.bookShelfId)"></i>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 底下悬浮窗口 -->
<view class="book-bottom" v-if="checkboOff">
<view class="bottom-box">
<view class="bottom-box-left">
<view class="top-btn" v-if="checkboOff && !checkAllOff" @click="checkAll">
<view>全选</view>
</view>
<view class="top-btn" v-if="checkboOff && checkAllOff" @click="checkNooAll">
<view>全不选</view>
</view>
</view>
<view class="bottom-box-right">
<view class="top-btn" @click="deleteBtn">
<view>移出书架({{selection.length}})</view>
</view>
</view>
</view>
</view>
<z-navigation></z-navigation>
<music-play :playData="playData"></music-play>
</view>
</template>
<script>
import musicPlay from '@/components/music.vue'
import $http from '@/config/requestConfig.js';
import {
mapState
} from 'vuex';
export default {
data() {
return {
playData:{},
bookNum: null, //
topX: '', //x轴
leftY: '', //y轴
selection: [], //多选
checkboOff: false, //显示多选开关
checkAllOff: false, //全选全不选
searchOff: false, //搜索
moreOff: false, //更多弹窗开关
moreId: '', //移除书籍ID
bookData: [],
bokMesDet:{}
};
},
//第一次加载
onLoad(e) {
// 隐藏原生的tabbar
uni.hideTabBar();
},
computed: {
...mapState(['userInfo'])
},
//页面显示
onShow() {
// 隐藏原生的tabbar
uni.hideTabBar();
this.getData();
},
// 下拉刷新
onPullDownRefresh() {
this.getData()
uni.stopPullDownRefresh()
},
//方法
components:{
musicPlay
},
methods: {
getData() {
this.bokMesDet.userId = this.userInfo.id
// 获取书架列表
this.$http
.post('book/bookshelf/getUserBookshelf', {
'userId': this.userInfo.id
})
.then(res => {
this.bookData = res.userBookshelf
console.log(res)
});
},
bookCardBtn(e, value, id) { //卡片点击按钮
//清空遗留数据
this.bookNum = null
this.topX = null
this.leftY = null
//开始脑残逻辑
this.bookNum = value //第几个波纹效果显示
this.topX = e.detail.x //获取相对于屏幕X轴坐标并赋值
const query = uni.createSelectorQuery().in(this);
query.select('#' + id).boundingClientRect(data => {
let cardT = JSON.stringify(data.top) //获取点击容器到顶距离
let cardY = e.detail.y //获取相对于屏幕y轴坐标并赋值
this.leftY = Number(cardY) - Number(cardT) //计算容器内点击Y轴坐标
}).exec();
if (this.checkboOff == true) { //多选状态下的事件
this.selection = []
this.topX = e.detail.x - 44
this.bookData[value].checked = !this.bookData[value].checked
this.bookData.forEach(item => {
if (item.checked === true) {
this.selection.push(item.bookShelfId) //ID值根据开发自定义 与上面checkbox的value绑定值相同
}
})
if (this.selection.length == this.bookData.length) {
this.checkAllOff = true
} else if (this.selection.length < this.bookData.length) {
this.checkAllOff = false
}
} else { //非多选状态下的事件
const that = this;
that.bokMesDet.id = that.bookData[value].bookShelfId
that.bokMesDet.bookId = that.bookData[value].bookid
// 加入阅读记录
$http.request({
url: "book/bookshelf/update",
method: "POST", // POST、GET、PUT、DELETE具体说明查看官方文档
data: that.bokMesDet,
header: { //默认 无 说明:请求头
'Content-Type': 'application/json'
},
}).then(function(res) {
if (res.code == 0) {
// 跳转页面
let chaId = 0
if (that.bookData[value].chapterNum != null) {
chaId = that.bookData[value].chapterNum-1
}
uni.navigateTo({
url: '../yRead/angbook?Id=' + that.bookData[value].bookid + '&cha=' + chaId
});
}
}).catch(function(error) {
//这里只会在接口是失败状态返回,不需要去处理错误提示
console.log(error);
});
}
//去TM的安卓APP、苹果APP、微信小程序、微信网页、H5的全兼容具体兼容那些版本我不测了。
},
managementBtn() { //管理按钮,打开多选和删除。
this.selection = []
this.checkboOff = true
this.bookData.forEach(item => {
this.$set(item, 'checked', false)
})
},
checkAll() { //全选按钮
//清空缓存
this.selection = []
//全选全不选显示切换
this.checkAllOff = !this.checkAllOff
//遍历数组
this.bookData.forEach(item => {
//新增属性
this.$set(item, 'checked', true)
this.selection.push(item.bookShelfId) //ID值根据开发自定义 与上面checkbox的value绑定值相同
})
console.log(this.selection)
},
checkNooAll() { //全不选按钮
//清空缓存
this.selection = []
//全选全不选显示切换
this.checkAllOff = !this.checkAllOff
//遍历数组
this.bookData.forEach(item => {
this.$set(item, 'checked', false)
})
console.log(this.selection)
},
omitBtn(value, id) { //更多,打开针对单个的删除处理。
console.log('你点了第' + value + '个更多id为' + id)
this.moreId = ''
this.moreId = id
this.moreOff = true
},
deleteBtn() { //移出书架按钮
const that = this;
if (that.selection.length > 0) {
$http.request({
url: "book/bookshelf/delete",
method: "POST", // POST、GET、PUT、DELETE具体说明查看官方文档
data: that.selection,
header: { //默认 无 说明:请求头
'Content-Type': 'application/json'
},
}).then(function(res) {
console.log(res)
if (res.code == 0) {
that.getData();
uni.showToast({
title: '移出书架成功!'
})
//移除书架后缓存清空复位
that.selection = []
that.checkboOff = false
that.checkAllOff = false
}
}).catch(function(error) {
//这里只会在接口是失败状态返回,不需要去处理错误提示
console.log(error);
});
} else {
}
},
searchBtn() { //搜索按钮
this.searchOff = true
},
cancelBtn() { //取消按钮
// 清空复位
this.searchOff = false
this.selection = []
this.checkboOff = false
this.checkAllOff = false
},
accomplish() { //完成按钮
// 清空复位
this.searchOff = false
this.selection = []
this.checkboOff = false
this.checkAllOff = false
},
examine() { //查看详情
this.moreOff = false
console.log('你查看了ID为' + this.moreId + '的书籍详情')
},
shiftOut() { //移出按钮
this.moreOff = false
console.log('你移出了ID为' + this.moreId + '的书籍')
}
},
};
</script>
<style lang="scss" scoped>
@import '@/style/mixin.scss';
$bookTop:46px;
$bookCardHeight:200upx;
$second: 0.6s;
.bookrack-body {
position: fixed;
top: 0;
/* #ifdef H5 */
top: 0;
/* #endif */
left: 0;
right: 0;
bottom: $navHeight;
overflow-y: auto;
}
.book-top {
height: $bookTop;
display: flex;
// border-bottom: 1px solid $brimColor;
padding: 0 20upx;
// background-color: #fff;
position: fixed;
width: 100%;
z-index: 100;
top: 150rpx;
.top-left {
flex: 1;
text-align: left;
line-height: $bookTop;
color: $dominantHue;
max-width: 100upx;
}
.top-right {
flex: 1;
line-height: $bookTop;
text-align: right;
color: $mediumGrey;
}
}
.book-rack::-webkit-scrollbar {
display: none
}
.book-rack {
padding-top: $bookTop+20;
.uni-radio-group uni-label,
uni-checkbox-group uni-label {
padding-right: 0 !important;
}
.book-card {
display: flex;
.book-checkbox {
flex: 1;
line-height: $bookCardHeight;
padding: 10px 0 10px $bleed;
min-width: 88upx;
max-width: 88upx;
box-sizing: border-box;
animation: book-interaction 0.1s;
}
@keyframes book-interaction {
0% {
min-width: 0upx;
max-width: 0upx;
}
100% {
min-width: 88upx;
max-width: 88upx;
}
}
.image-text {
flex: 1;
display: flex;
height: $bookCardHeight + 40upx;
padding: 10px $bleed 10px $bleed;
position: relative;
overflow: hidden;
left: 0px;
right: 0px;
.book-left {
flex: 1;
min-width: 170upx;
max-width: 170upx;
height: $bookCardHeight;
position: relative;
z-index: 10;
.book-img {
width: 150upx;
height: $bookCardHeight;
border-radius: 8upx;
overflow: auto;
background-color: $skeletonColor;
}
}
.book-right {
position: relative;
flex: 1;
height: $bookCardHeight;
z-index: 10;
.book-text {
padding: 4upx 0;
height: 100%;
box-sizing: border-box;
.head {
font-weight: bold;
font-size: 30upx;
height: 32upx;
line-height: 32upx;
color: $blackAll;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
.author {
padding-top: 24upx;
font-size: 28upx;
color: $mediumGrey;
height: calc(100% - 8upx - 24upx - 28upx);
}
.schedule {
line-height: 28upx;
height: 28upx;
display: flex;
.schedule-text {
flex: 1;
font-size: 28upx;
color: $mediumGrey;
}
.book-icon {
flex: 1;
min-width: 55upx;
max-width: 55upx;
text-align: right;
.omit {
font-size: 40upx;
line-height: 28upx;
color: $lightGray;
padding: 10upx;
}
}
}
}
}
}
}
}
.top-btn {
height: 48upx;
line-height: 30upx;
padding: 0upx 12upx;
font-size: 28upx;
display: inline-block;
color: #54a966;
font-weight: bold;
margin-top: 14px;
.icon_search {
background-image: url('@/static/icon/map_ic_search.png');
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
width: 35upx;
height: 33upx;
margin-right: 20upx;
display: block;
}
}
.top-btn:active {
background-color: $rippleBg;
}
//波纹效果
.ripple {
width: 1px;
height: 1px;
position: absolute;
z-index: -5;
background-color: $rippleBg;
box-shadow: 0 0 0px 500px $rippleBg;
border-radius: 50%;
animation: myfirst $second;
opacity: 0.6;
}
@keyframes myfirst {
from {
box-shadow: 0 0 0px 30px $rippleBg;
opacity: 1;
}
to {
box-shadow: 0 0 0px 500px $rippleBg;
opacity: 0.5;
}
}
// 底部悬浮
.book-bottom {
position: fixed;
left: 0;
bottom: 50rpx;
right: 0;
height: $navHeight + 30px;
background-color: #fff;
z-index: 110;
border-top: 1px solid $brimColor;
.bottom-box {
height: $navHeight+30px;
padding: 0 15upx;
line-height: $navHeight;
color: $dominantHue;
display: flex;
.bottom-box-left {
flex: 1;
text-align: left;
}
.bottom-box-right {
flex: 1;
text-align: right;
}
}
}
//复选框 原生的处理起来有点难
.checkboxcard {
width: 38upx;
height: 38upx;
border-radius: 8upx;
border: 1px solid #DCDFE6;
margin-top: calc(100upx - 20upx)
}
.checkboxactiva {
border: 1px solid $dominantHue;
box-shadow: 0 0 2px rgba(0, 134, 231, 0.5);
}
.check {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.check::after {
margin-top: -6upx;
width: 6px;
height: 12px;
border-style: solid;
border-color: $dominantHue;
border-width: 0 2px 2px 0;
-webkit-transform: rotateZ(45deg);
content: " ";
animation: check-interaction 0.1s;
}
@keyframes check-interaction {
0% {
width: 0px;
height: 0px;
margin-top: -6upx;
margin-right: 0px;
}
35% {
width: 6px;
height: 0px;
}
100% {
height: 12px;
margin-top: -6upx;
margin-right: 0px;
}
}
.input-cancel {
display: flex;
.cancel-left {
flex: 1;
.uni-input {
line-height: 36px;
height: 36px;
font-size: 28upx;
margin-top: calc((46px - 36px) / 2);
background-color: #f4f4f4;
border-radius: 8upx;
padding: 0 20upx;
text-align: left;
}
}
.cancel-right {
flex: 1;
max-width: 85upx;
min-width: 85upx;
}
}
.search-activa {
z-index: 30;
top: 20px;
// bottom: 0px;
animation: search-interaction 0.2s;
}
.subject {
transition: top 0.2s;
}
@keyframes search-interaction {
0% {
top: $barHeight + 10px;
}
100% {
top: 20px;
}
}
.more-shade {
position: fixed;
background-color: rgba(0, 0, 0, 0.4);
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;
}
.more {
position: fixed;
top: calc((100% - 300upx) / 2);
left: 10%;
right: 10%;
background-color: #fff;
border-radius: 4upx;
.more-list {
height: 100upx;
line-height: 100upx;
font-size: 30upx;
padding: 0 40upx;
color: $dominantHue;
}
.more-underline {
border-bottom: 1px solid #F1F1F1;
}
.remove {
color: $redAll;
}
}
.bookrack-active {
bottom: $navHeight + 12px;
}
/*苹果x适配 H5APP*/
@media only screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) {
.book-bottom {
height: $navHeight + $navBoxHeight + 55px;
}
.bookrack-body {
top: 0;
bottom: $navHeight + $navBoxHeight;
/* #ifdef H5 */
top: 0;
bottom: $navHeight;
/* #endif */
}
.bookrack-active {
bottom: $navHeight + $navBoxHeight + 12px;
}
.search-activa {
z-index: 30;
top: $barHeight;
animation: search-interaction 0.2s;
}
@keyframes search-interaction {
0% {
top: $barHeight + $barTopHeight;
}
100% {
top: $barHeight;
}
}
}
/*苹果xs适配 H5APP*/
@media only screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) {
.book-bottom {
height: $navHeight + $navBoxHeight + 55px;
}
.bookrack-body {
top: 0;
bottom: $navHeight + $navBoxHeight;
/* #ifdef H5 */
top: 0;
bottom: $navHeight;
/* #endif */
}
.bookrack-active {
bottom: $navHeight + $navBoxHeight + 12px;
}
.search-activa {
z-index: 30;
top: $barHeight;
animation: search-interaction 0.2s;
}
@keyframes search-interaction {
0% {
top: $barHeight + $barTopHeight;
}
100% {
top: $barHeight;
}
}
}
/*苹果xr适配 H5APP*/
@media only screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) {
.book-bottom {
height: $navHeight + $navBoxHeight + 30px;
}
.bookrack-body {
top: 0;
bottom: $navHeight + $navBoxHeight;
/* #ifdef H5 */
top: 0;
bottom: $navHeight;
/* #endif */
}
.bookrack-active {
bottom: $navHeight + $navBoxHeight + 30px;
}
.search-activa {
z-index: 30;
top: $barHeight;
animation: search-interaction 0.2s;
}
@keyframes search-interaction {
0% {
top: $barHeight + $barTopHeight;
}
100% {
top: $barHeight;
}
}
}
</style>