Commit 7375eeb9 authored by jyx's avatar jyx

更新首页UI

parent c78d0055
......@@ -36,7 +36,7 @@
this.globalData.bottomSafePadding = Math.max(res.screenHeight - res.safeArea.bottom, 12);
// #endif
try {
let value = uni.getStorageSync('token') || '';
let value = uni.getStorageSync('TOKEN') || '';
let inviteUId = uni.getStorageSync('inviteUId') || '';
if (!inviteUId && options.query.inviteUId) {
......
// export default {
// created() {
// //#ifdef MP-WEIXIN
// wx.showShareMenu({
// withShareTicket: true,
// menus: ['shareAppMessage', 'shareTimeline']
// });
// //#endif
// },
// }
export default {
data() {
......
......@@ -25,10 +25,13 @@ export default class Book {
createTime,
tagList,
isUnlock,
free,
charge,
bookLegumes,
lockRate
lockRate,
shortis,
articleChapterList,
freeNum,
carouselUrl,
isChecked
} = param || {}
this.id = id;
this.title = title;
......@@ -56,9 +59,12 @@ export default class Book {
this.categoryId = categoryId;
this.createTime = createTime;
this.isUnlock = isUnlock;
this.charge = charge;
this.free = free;
this.bookLegumes = bookLegumes;
this.lockRate = lockRate;
this.shortis = shortis;
this.freeNum = freeNum;
this.carouselUrl = carouselUrl;
this.isChecked = isChecked;
this.articleChapterList = articleChapterList;
}
}
\ No newline at end of file
import Book from "../../../common/models/Book";
import Book from "../models/Book.js";
import {
getTimeDesc
} from "../../../common/utils/timeUtil";
} from "../utils/timeUtil";
export default class BookshelfBookItem extends Book {
constructor(param) {
......
......@@ -167,7 +167,7 @@ function collectionBook(isCollected, bookId, callback) {
apiPOST({
url,
data: {
articleId:bookId
articleId: bookId
},
callback
})
......@@ -284,6 +284,14 @@ function getBookBeanPackData(callback) {
})
}
function getCollects(callback) {
apiPOST({
url: "/book/collectList",
data: {},
callback
})
}
/**
* 解锁书籍
......@@ -299,7 +307,43 @@ function buyBookWithBookBean(bookId, callback) {
callback
})
}
/**
* 获取推荐书籍
* @param {Object} flag
* @param {Object} quantity
*/
function getRecommendV1(flag, quantity, callback) {
apiPOST({
url: `/book/recommendv1`,
data: {
flag: flag,
quantity: quantity
},
callback
})
}
/**
* 猜你喜欢
* @param {Object} flag
*/
function getArticleLike(quantity, callback) {
apiPOST({
url: `/book/articleLike`,
data: {
quantity: quantity
},
callback
})
}
module.exports = {
getRecommendV1,
getArticleLike,
getCollects,
getOpens,
getReadTimeCount,
startCountReadTime,
......
......@@ -17,7 +17,17 @@ function gotoBookSearchPage(searchType = ENUM_SEARCH_TYPE.WAREHOUSE, keyword) {
}
// 文章详情
function gotoBookContentPage(bookId) {
function gotoBookContentPage(bookId, shortis) {
if (shortis && shortis == 0) {
gotoShortBookContentPage(bookId)
} else {
gotoLongBookContentPage(bookId)
}
}
// 短篇文章详情
function gotoShortBookContentPage(bookId) {
// 短篇小说
uni.navigateTo({
url: `/page-subs/sub_A/book-content/book-content`,
success: (res) => {
......@@ -28,6 +38,18 @@ function gotoBookContentPage(bookId) {
})
}
// 长篇文章详情
function gotoLongBookContentPage(bookId) {
uni.navigateTo({
url: `/page-subs/sub_A/book-long-content/book-long-content`,
success: (res) => {
res.eventChannel.emit("openBookContentPage", {
bookId
})
}
})
}
// 文章封面
function gotoBookCoverPage(bookId) {
return;
......
......@@ -247,8 +247,7 @@ function saveToken(token) {
function readToken() {
if (!LOCAL_TOKEN) {
// LOCAL_TOKEN = readStorage(KEY_STORAGE_TOKEN)
LOCAL_TOKEN = readStorage('token')
LOCAL_TOKEN = readStorage(KEY_STORAGE_TOKEN)
}
return LOCAL_TOKEN;
}
......
<template>
<view class="banneritem">
<swiper :autoplay="true" :interval="2000" :duration="500">
<swiper-item @click="handleBanner(item)" v-for='(item, index) in bannerList' :key='index'
style="border-radius: 20rpx;">
<image class="banner-img" :src="item.carouselUrl" mode="aspectFill"></image>
</swiper-item>
</swiper>
</view>
</template>
<script>
import {
gotoBookContentPage
} from '../../common/services/page-route.js';
import {
getRecommendV1
} from "../../common/services/index.js"
import BookshelfBookItem from '../../common/models/BookshelfBookItem.js';
import SystemInfoMixin from "../../common/mixins/system-info-mixin.js"
export default {
mixins: [SystemInfoMixin],
data() {
return {
bannerList: []
};
},
methods: {
handleBanner(e) {
gotoBookContentPage(e.id, e.shortis)
},
initData() {
this.refreshList();
},
// 刷新数据列表
refreshList() {
getRecommendV1('carousel', 10, (success, data) => {
if (success) {
this.changeData(data)
}
})
},
changeData(e) {
this.bannerList = e.records.map(item => {
return new BookshelfBookItem(item)
})
},
}
}
</script>
<style lang="scss">
.banneritem {
margin: 20rpx 30rpx 0 30rpx;
// height: 310rpx;
.banner-img {
height: 320rpx;
}
}
</style>
\ No newline at end of file
<template>
<view class="book-list-item" @click="tapItem">
<view class="cover-box item">
<!-- <image v-show="imageError" class="cover" src="/static/images/image_error.png" mode="aspectFill"></image> -->
<image class="cover" :src="item.avatar" mode="aspectFill"></image>
</view>
<view class="c-flex_column">
<view class="c-flex_row row" style="justify-content: space-between;padding-left:20rpx;">
<view class="c-flex_row row" style="justify-content: space-between;">
<view class="c-flex_column c-justify_center item">
<view class="title">
{{item.title}}
{{item.title?item.title:''}}
</view>
</view>
<view class="close-button item" v-if='showClose'>
......@@ -17,9 +16,9 @@
</view>
</view>
<view class="c-flex_row row">
<view class="c-flex_column c-justify_between content c-flex_1 item">
<view class="c-flex_column c-justify_between c-flex_1 item">
<view class="desc row">
{{item.summary}}
{{item.summary?item.summary:''}}
</view>
<view class="c-flex_row c-align_center label-box row">
<slot name="footer">
......@@ -60,7 +59,11 @@
watch: {},
computed: {
showCategory: function() {
return this.item.categoryName
if (this.item && this.item.categoryName) {
return true
} else {
return false
}
},
showErrorImage: function() {
return this.imageError;
......@@ -99,7 +102,7 @@
.book-list-item {
display: flex;
flex-direction: row;
padding: 20rpx 40rpx;
padding: 20rpx 20rpx;
.row {
margin-bottom: 20rpx;
......@@ -121,6 +124,9 @@
font-size: 32rpx;
font-weight: 700;
color: #333;
overflow: hidden;
white-space: nowrap; //单行显示
text-overflow: ellipsis; //超出部分省略号显示
}
.close-button {
......@@ -150,7 +156,7 @@
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
font-size: 26rpx;
......@@ -159,12 +165,16 @@
.label-box {
flex-wrap: wrap;
flex-direction: row;
overflow: auto;
.label {
padding: 5rpx 10rpx;
font-size: 20rpx;
margin-right: 20rpx;
border-radius: 10rpx;
flex-shrink: 0;
display: inline-block;
}
.label-color-1 {
......@@ -173,8 +183,8 @@
}
.label-color-2 {
color: #3d99fd;
background: #d8ebff;
color: #F1413C;
background: #FEF3F3;
}
.label-color-3 {
......@@ -186,8 +196,8 @@
.cover-box {
.cover {
width: 150rpx;
height: 200rpx;
width: 165rpx;
height: 220rpx;
border-radius: 15rpx;
}
}
......
<template>
<view class="cover-box" @click="tapItem">
<image v-if="!last" class="cover" :style="'height:'+ coverHeight + 'rpx;'" :src="item.avatar" mode="aspectFill">
</image>
<image v-else class="cover" :style="'height:'+ coverHeight + 'rpx;'"
src="https://mints-pkg.oss-cn-beijing.aliyuncs.com/pkg/img/bg_book_more.png" mode="scaleToFill"></image>
<view class="title" v-if="!last">
{{item.title}}
</view>
<view class="c-flex_row c-align_center label-box" v-if="!last">
<slot name="footer">
<view class="label label-color-1" v-if='showCategory'>
{{item.categoryName}}
</view>
<view class="label label-color-2" v-for='(label, labelIndex) in item.tagList' :key='labelIndex'>
{{label.name}}
</view>
</slot>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: function() {
return {}
}
},
last: {
type: Boolean,
default: false
},
coverHeight: {
type: Number,
default: 220
}
},
data: function() {
return {
imageError: true
}
},
watch: {},
computed: {
showCategory: function() {
return this.item.categoryName
},
showErrorImage: function() {
return this.imageError;
},
hideErrorImage: function() {
return !this.imageError
}
},
methods: {
tapItem() {
this.$emit("tapItem", {
detail: {
data: this.item
}
})
},
loadImage() {
this.imageError = false;
},
errorImage() {
this.imageError = true
}
}
}
</script>
<style lang="scss" scoped>
.cover-box {
display: flex;
flex-direction: column;
.title {
width: 100%;
font-size: 26rpx;
margin-top: 10rpx;
color: #383B3D;
height: 70rpx;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2; //元素几行显示
-webkit-box-orient: vertical;
}
.cover {
width: 100%;
border-radius: 15rpx;
}
.label-box {
margin-top: 6rpx;
display: flex;
flex-direction: row;
overflow: auto;
.label {
padding: 5rpx 10rpx;
font-size: 20rpx;
margin-right: 20rpx;
border-radius: 10rpx;
flex-shrink: 0;
display: inline-block;
}
.label-color-1 {
background: #faefe6;
color: #cc6008;
}
.label-color-2 {
color: #F1413C;
background: #FEF3F3;
}
.label-color-3 {
background: #ff8787;
color: #ff3737;
}
}
}
</style>
\ No newline at end of file
<template>
<view class="book-list-item" @click="tapItem">
<view class="cover-box">
<image class="cover" :src="item.avatar" mode="aspectFill"></image>
</view>
<view class="c-flex_column">
<view class="c-flex_row row" style="justify-content: space-between;">
<view class="c-flex_column c-justify_center item">
<view class="title">
{{item.title?item.title:''}}
</view>
</view>
</view>
<view class="c-flex_row row">
<view class="c-flex_column c-justify_between c-flex_1 item">
<view class="desc row">
{{item.summary?item.summary:''}}
</view>
<view class="label-box row">
<slot name="footer">
<view class="label label-color-1" v-if='showCategory'>
{{item.categoryName}}
</view>
<view class="label label-color-2" v-for='(label, labelIndex) in item.tagList'
:key='labelIndex'>
{{label.name}}
</view>
</slot>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: function() {
return {}
}
}
},
data: function() {
return {
imageError: true
}
},
watch: {},
computed: {
showCategory: function() {
if (this.item && this.item.categoryName) {
return true
} else {
return false
}
},
showErrorImage: function() {
return this.imageError;
},
hideErrorImage: function() {
return !this.imageError
}
},
methods: {
tapItem() {
this.$emit("tapItem", {
detail: {
data: this.item
}
})
},
loadImage() {
this.imageError = false;
},
errorImage() {
this.imageError = true
}
}
}
</script>
<style lang="scss" scoped>
.book-list-item {
display: flex;
flex-direction: row;
// padding: 20rpx 20rpx;
.row {
margin-bottom: 20rpx;
}
.row:last-child {
margin-bottom: 0;
}
.item {
width: 140rpx;
}
.title {
width: 100%;
font-size: 26rpx;
margin-top: 10rpx;
color: #383B3D;
height: 70rpx;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2; //元素几行显示
-webkit-box-orient: vertical;
}
.desc {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
font-size: 26rpx;
color: #999
}
.label-box {
display: flex;
flex-direction: row;
overflow: auto;
.label {
padding: 5rpx 10rpx;
font-size: 20rpx;
margin-right: 20rpx;
border-radius: 10rpx;
flex-shrink: 0;
display: inline-block;
}
.label-color-1 {
background: #faefe6;
color: #cc6008;
}
.label-color-2 {
color: #F1413C;
background: #FEF3F3;
}
.label-color-3 {
background: #ff8787;
color: #ff3737;
}
}
}
.cover-box {
margin-right: 20rpx;
.cover {
width: 165rpx;
height: 260rpx;
border-radius: 15rpx;
}
}
</style>
\ No newline at end of file
......@@ -2,12 +2,12 @@
<view class="search-box" @click="search">
<view class="search-zone c-flex_row c-align_center">
<view class="item">
<uni-icons type='search' size='28' color="#e5e5e5"></uni-icons>
<uni-icons type='search' size='26' color="#949CA4"></uni-icons>
</view>
<input class="item c-flex_1" placeholder="搜索书名/作者名" disabled />
<view class="mbutton item">
<!-- <view class="mbutton item">
搜索
</view>
</view> -->
</view>
</view>
</template>
......@@ -39,10 +39,11 @@
<style lang="scss" scoped>
.search-box {
background: transparent;
padding: 10rpx 20rpx;
padding: 10rpx 30rpx;
.search-zone {
width: 100%;
// width: 100%;
border: solid 1rpx #FFE2E2;
border-radius: 35rpx;
background: #fff;
padding: 4rpx;
......@@ -50,6 +51,7 @@
.item {
margin-left: 20rpx;
color: #949CA4;
}
.mbutton {
......
<template>
<scroll-view scroll-y style="height: 100%;">
<book-search-box id='search'></book-search-box>
<Banner ref='banner'></Banner>
<RecommendList ref='recommendList1' :listType="1"></RecommendList>
<RecommendList ref='recommendList2' :listType="2"></RecommendList>
<view style="height: 20rpx;"></view>
</scroll-view>
</template>
<script>
import {
gotoBookContentPage
} from '../../common/services/page-route'
import {
getFirstShow
} from "./services/index.js"
import RecommendList from "../recommend-list/recommend-list.vue";
import Banner from "../banner/banner.vue";
import SystemInfoMixin from "../../common/mixins/system-info-mixin.js"
export default {
mixins: [SystemInfoMixin],
components: {
RecommendList,
Banner
},
data() {
return {
listHeight: 0
};
},
onReady() {
// this.initHeight();
this.initData();
},
onShow() {},
onUnload() {
// 移除监听
removeUserInfoChangeWatch(this);
},
methods: {
show() {
this.getFirstShowData();
},
hide() {
},
getFirstShowData() {
getFirstShow((success, data) => {
if (success) {
setTimeout(() => {
// 匹配用户直接跳转小说
if (data.articleMsg != null) {
gotoBookContentPage(data.articleMsg.id, data.articleMsg.shortis);
}
}, 800);
}
})
},
initData() {
this.refreshList();
},
// 刷新数据列表
refreshList() {
let ref2 = this.$refs.recommendList1;
if (ref2) {
ref2.refreshList();
}
let banner = this.$refs.banner;
if (banner) {
banner.refreshList();
}
let ref = this.$refs.recommendList2;
if (ref) {
ref.refreshList();
}
},
initHeight() {
const query = uni.createSelectorQuery().in(this);
query.exec((res) => {
let result = 0;
res.forEach(item => {
result = result + item.height;
})
this.listHeight = this.windowHeight - result;
})
},
}
}
</script>
<style lang="scss">
</style>
\ No newline at end of file
<template>
<view class="bookshelf">
<read-time-count-row id='count' ref='timeCount'></read-time-count-row>
<view class="bookitem" v-if="dataList.length>0">
<book-list-item2 class="item" v-for='(item, index) in dataList' :key='index' :item='item'
:last="index>=dataList.length-1" @tapItem='tapItem($event, index)' @close='tapClose($event, index)'>
</book-list-item2>
</view>
<c-shelf-empty v-else></c-shelf-empty>
</view>
</template>
<script>
import common from '@/mixins/common';
import {
getCollects,
} from "../../../common/services/index.js"
import {
gotoBookContentPage
} from '../../../common/services/page-route';
import BookshelfBookItem from '../../../common/models/BookshelfBookItem.js';
export default {
mixins: [common],
props: {
height: {
type: Number,
default: 0
},
},
data: function() {
return {
dataList: [],
}
},
methods: {
refreshList() {
getCollects((success, data) => {
if (success) {
this.changeData(data)
}
})
this.refreshTimeCount()
},
refreshTimeCount() {
let ref = this.$refs.timeCount;
if (ref) {
ref.refresh()
}
},
changeData(e) {
this.dataList = e.records.map(item => {
return new BookshelfBookItem(item)
})
this.dataList.push({})
},
tapItem(e, index) {
if (index >= this.dataList.length - 1) {
uni.$emit('goWareHouse')
return
}
gotoBookContentPage(e.detail.data.id, e.detail.data.shortis)
}
}
}
</script>
<style lang="scss" scoped>
.bookshelf {
display: flex;
flex-direction: column;
border-radius: 20rpx;
background-color: white;
margin: 30rpx;
.bookitem {
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding-left: 20rpx;
.item {
width: 22%;
margin-bottom: 20rpx;
margin-right: 20rpx;
}
.item:last-child {
margin-bottom: 0;
margin-right: 0;
}
}
}
</style>
\ No newline at end of file
import {
apiGET,
apiPOST
} from "../../../common/utils/apiRequest.js"
function getFirstShow(callback) {
apiPOST({
url: "/book/firstArticle",
callback
})
}
module.exports = {
getFirstShow
}
\ No newline at end of file
<template>
<z-paging>
<c-navi id='navi'></c-navi>
<book-search-box id='search' :searchType='searchType'></book-search-box>
<read-time-count-row id='count' ref='timeCount' @resize='resizeTimeCount'></read-time-count-row>
<BookshelfList ref='bookList' :height='listHeight'></BookshelfList>
<c-login></c-login>
</z-paging>
<scroll-view scroll-y style="height: 100%;">
<BookshelfList ref='bookList' v-on:showEditBarR="showEditBarR"></BookshelfList>
<RecommendList ref='recommendList' :listType="0"></RecommendList>
<view style="height: 20rpx;"></view>
</scroll-view>
</template>
<script>
import BookshelfList from "./components/bookshelf-list.vue";
import RecommendList from "../recommend-list/recommend-list.vue";
import SystemInfoMixin from "../../common/mixins/system-info-mixin.js"
import {
watchUserInfoChange,
removeUserInfoChangeWatch
} from "../../common/services/userServices.js";
import {
ENUM_SEARCH_TYPE
} from "../../static/enums/enum_value";
import {
removeCollectionChangeWatch,
watchCollectionChange
......@@ -25,30 +17,27 @@
export default {
mixins: [SystemInfoMixin],
components: {
BookshelfList
BookshelfList,
RecommendList
},
data() {
return {
searchType: ENUM_SEARCH_TYPE.BOOKSHELF,
listHeight: 0
};
},
onReady() {
this.initHeight();
// 监听用户变动
watchUserInfoChange((info) => {
if (info.userInfo) {
this.initData();
}
}, this)
// 监听收藏变动
watchCollectionChange(() => {
this.refreshList();
this.refreshCollect();
}, this);
},
onShow() {
// 更新阅读时间统计
this.refreshTimeCount();
let ref = this.$refs.bookList;
if (ref) {
ref.refreshTimeCount();
}
},
onUnload() {
// 移除监听
......@@ -57,55 +46,32 @@
},
methods: {
show() {
this.$refs.timeCount.refresh()
this.initHeight();
// 监听用户变动
watchUserInfoChange((info) => {
if (info.userInfo) {
this.initData();
let ref = this.$refs.bookList;
if (ref) {
ref.refreshTimeCount();
}
}, this)
// 监听收藏变动
watchCollectionChange(() => {
this.refreshList();
}, this);
},
hide() {
},
resizeTimeCount() {
this.initHeight();
},
initData() {
this.refreshList();
},
// 初始化刷新
initRefresh() {
let ref = this.$refs.bookList;
if (ref) {
ref.initRefresh();
}
this.refreshCollect();
this.refreshBook();
},
// 刷新数据列表
refreshList() {
refreshCollect() {
let ref = this.$refs.bookList;
if (ref) {
ref.refreshList();
}
},
refreshTimeCount() {
let ref = this.$refs.timeCount;
refreshBook() {
let ref = this.$refs.recommendList;
if (ref) {
ref.refresh();
ref.refreshList();
}
},
initHeight() {
const query = uni.createSelectorQuery().in(this);
query.select("#navi").boundingClientRect();
query.select("#search").boundingClientRect();
query.select("#count").boundingClientRect();
query.select("#count").boundingClientRect();
query.exec((res) => {
let result = 0;
res.forEach(item => {
......@@ -114,6 +80,18 @@
this.listHeight = this.windowHeight - result;
})
},
showEditBarR(b) {
this.$emit("showEditBarH", b);
},
fullChoice() {
this.$refs.bookList.fullChoice()
},
noChoice() {
this.$refs.bookList.noChoice()
},
deleteCollect() {
this.$refs.bookList.deleteCollect()
},
}
}
</script>
......
<template>
<view>
<c-list ref='list' :showShelfEmpty="true" flag='bookshelf' :needLogin="true" :height="height" url='/book/collectList'
:param="requestParam" @change='changeData' method="POST">
<book-list-item v-for='(item, index) in dataList' :key='index' :item='item'
@tapItem='tapItem($event, index)' @close='tapClose($event, index)'>
<template v-slot:footer>
<view class="c-flex_row c-aligns_center">
<uni-icons type='calendar' size="16" color="#999"></uni-icons>
<view class="info">
{{item.lastReadTime}} 前阅读过
<view class="bookshelf">
<view class="topitem">
<read-time-count-row id='count' ref='timeCount'></read-time-count-row>
<view @click="showEditBar = !showEditBar">
<image v-if="showEditBar" mode="widthFix" src="@/static/images/close.png">
</image>
<image v-else mode="widthFix" src="@/static/images/edit.png">
</image>
</view>
</view>
</template>
</book-list-item>
</c-list>
<view class="bookitem" v-if="dataList.length>0">
<shelf-list-item class="item" v-for='(item, index) in dataList' :key='index' :item='item'
:last="index>=dataList.length-1" @tapItem='tapItem($event, index)' @cbClick='cbClick(index)'
:showChecked="showEditBar" v-on:showEditBarR="showEditBarR">
</shelf-list-item>
</view>
<c-shelf-empty v-else></c-shelf-empty>
</view>
</template>
<script>
import SystemInfoMixin from "../../../common/mixins/system-info-mixin.js"
import ShelfListItem from "./shelf-list-item.vue";
import ReadTimeCountRow from "@/components/read-time-count-row/read-time-count-row.vue";
import {
getCollects
} from "../../../common/services/index.js"
import {
gotoBookContentPage
} from '../../../common/services/page-route';
import {
isEmpty
} from '../../../common/utils/util';
import BookshelfBookItem from '../models/BookshelfBookItem';
import BookshelfBookItem from '../../../common/models/BookshelfBookItem.js';
import {
collectionBook,
noticeCollectionListChange
} from "../../../common/services/index.js"
export default {
mixins: [SystemInfoMixin],
props: {
height: {
type: Number,
default: 0
},
},
components: {
ShelfListItem,
ReadTimeCountRow
},
data: function() {
return {
dataList: [],
bookMore: 'https://mints-pkg.oss-cn-beijing.aliyuncs.com/pkg/img/bg_book_more.png',
isEditStyle: false,
showEditBar: false
}
},
computed: {
requestParam: function() {
return {}
watch: {
showEditBar: {
handler(newValue, oldValue) {
this.$emit("showEditBarR", newValue)
}
},
},
methods: {
initRefresh() {
if (isEmpty(this.dataList)) {
this.refreshList();
refreshList() {
getCollects((success, data) => {
if (success) {
this.changeData(data)
}
})
this.refreshTimeCount()
},
refreshList() {
let ref = this.$refs.list;
refreshTimeCount() {
let ref = this.$refs.timeCount;
if (ref) {
ref.onPullRefreshing();
ref.refresh()
}
},
changeData(e) {
console.log(e)
this.dataList = e.detail.data.map(item => {
this.dataList = e.records.map(item => {
return new BookshelfBookItem(item)
})
if (this.dataList.length > 0) {
this.dataList.push(
new BookshelfBookItem({}))
}
},
tapItem(e, index) {
gotoBookContentPage(e.detail.data.id)
},
tapClose(e, index) {
let item = e.detail.data;
uni.showModal({
title: "确认移除",
content: `是否确认从书架中移除《${item.title}》`,
success: (res) => {
if (res.confirm) {
collectionBook(false, item.id, (success, data) => {
if (success) {
this.dataList.splice(index, 1);
this.$forceUpdate();
noticeCollectionListChange(item.id, false);
if (index >= this.dataList.length - 1) {
uni.$emit('goWareHouse')
return
}
gotoBookContentPage(e.detail.data.id, e.detail.data.shortis)
},
showEditBarR(e) {
this.showEditBar = e
},
changeEditStyle(e) {
this.isEditStyle = e
if (!this.isEditStyle) {
this.noChoice()
}
},
cbClick(index) {
let newData = this.dataList[index]
newData.isChecked = !newData.isChecked
this.$set(this.dataList, index, newData)
},
longClick(index) {
this.isEditStyle = true
this.dataList[index].isChecked = true
},
fullChoice() {
for (let i = 0; i < this.dataList.length; i++) {
this.dataList[i].isChecked = true
}
},
noChoice() {
for (let i = 0; i < this.dataList.length; i++) {
this.dataList[i].isChecked = false
}
},
deleteCollect() {
let str = ''
for (let i = 0; i < this.dataList.length; i++) {
if (this.dataList[i].isChecked) {
if (this.dataList[i].id) {
str += (this.dataList[i].id + ',')
}
}
})
}
collectionBook(false, str, (success, data) => {
if (success) {
this.showEditBar = false
this.refreshList()
// noticeCollectionListChange('', false)
}
})
}
},
}
}
</script>
<style lang="scss" scoped>
.info {
font-size: 26rpx;
color: #999;
margin-left: 10rpx;
.bookshelf {
display: flex;
flex-direction: column;
border-radius: 20rpx;
background-color: white;
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.1);
margin: 30rpx;
.topitem {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 0 30rpx;
image {
width: 50rpx;
height: 50rpx;
}
}
.bookitem {
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding-left: 20rpx;
.item {
width: 30%;
margin-bottom: 20rpx;
margin-right: 20rpx;
}
.item:last-child {
// margin-bottom: 0;
// margin-right: 0;
}
}
}
</style>
\ No newline at end of file
<template>
<view class="cover-box" @click.stop="tapItem" @longpress.stop="longClick">
<!-- <image v-show="imageError" class="cover" src="/static/images/image_error.png" mode="aspectFill"></image> -->
<image v-if="!last" class="cover" :src="item.avatar" mode="aspectFill">
</image>
<image v-else class="cover" src="https://mints-pkg.oss-cn-beijing.aliyuncs.com/pkg/img/bg_book_more.png"
mode="scaleToFill"></image>
<view class="title" v-if="!last">
{{item.title}}
</view>
<view class="c-flex_row c-align_center label-box" v-if="!last">
<slot name="footer">
<view class="label label-color-1" v-if='showCategory'>
{{item.categoryName}}
</view>
<view class="label label-color-2" v-for='(label, labelIndex) in item.tagList' :key='labelIndex'>
{{label.name}}
</view>
</slot>
</view>
<view v-if="isEditStyle && !last" @click.stop="cbClick" style="position: absolute;background: #000000; opacity: 0.6;width: 92%;height: 96%;top: 0;border-radius:20rpx;
padding-left: 20rpx;padding-top: 20rpx;">
<image v-if="item.isChecked" src="@/static/images/ic_selected.png" style="width: 50rpx;height: 50rpx;" />
<image v-else src="@/static/images/ic_unselected.png" style="width: 50rpx;height: 50rpx;" />
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: function() {
return {}
}
},
last: {
type: Boolean,
default: false
},
showChecked: {
type: Boolean,
default: false
}
},
computed: {
showCategory: function() {
return this.item.categoryName
},
showErrorImage: function() {
return this.imageError;
},
hideErrorImage: function() {
return !this.imageError
}
},
watch: {
showChecked: {
handler(newValue, oldValue) {
this.isEditStyle = newValue
}
},
isEditStyle: {
handler(newValue, oldValue) {
this.$emit("showEditBarR", newValue)
}
},
},
data() {
return {
isEditStyle: false
};
},
methods: {
longClick() {
if (!this.isEditStyle) {
this.isEditStyle = true
this.cbClick()
}
},
tapItem() {
this.$emit("tapItem", {
detail: {
data: this.item
}
})
},
loadImage() {
this.imageError = false;
},
errorImage() {
this.imageError = true
},
changeEditStyle(e) {
this.isEditStyle = e
},
cbClick() {
this.$emit("cbClick")
}
}
}
</script>
<style lang="scss" scoped>
.cover-box {
display: flex;
flex-direction: column;
position: relative;
.title {
width: 100%;
font-size: 26rpx;
margin-top: 10rpx;
color: #383B3D;
height: 70rpx;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2; //元素几行显示
-webkit-box-orient: vertical;
}
.cover {
width: 100%;
height: 300rpx;
border-radius: 15rpx;
}
.label-box {
margin-top: 6rpx;
display: flex;
flex-direction: row;
overflow: auto;
.label {
padding: 5rpx 10rpx;
font-size: 20rpx;
margin-right: 20rpx;
border-radius: 10rpx;
flex-shrink: 0;
display: inline-block;
}
.label-color-1 {
background: #faefe6;
color: #cc6008;
}
.label-color-2 {
color: #F1413C;
background: #FEF3F3;
}
.label-color-3 {
background: #ff8787;
color: #ff3737;
}
}
}
</style>
\ No newline at end of file
module.exports = {}
\ No newline at end of file
import {
apiGET,
apiPOST
} from "../../../common/utils/apiRequest.js"
module.exports = {
}
\ No newline at end of file
<template>
<scroll-view class="c-list" :style="[scrollStyle]" scroll-y :refresher-enabled='ableRefresh'
refresher-threshold='100' :enable-flex='true' :refresher-triggered='refreshTrigger' @refresherrefresh='refresh'
@scrolltolower='onLoadMore'>
refresher-default-style="black" refresher-threshold='100' :enable-flex='true'
:refresher-triggered='refreshTrigger' @refresherrefresh='refresh' @scrolltolower='onLoadMore'>
<view class="content" :style="[contentStyle]">
<template v-if='showCover'>
<slot name="cover"></slot>
</template>
<template v-else-if='showEmpty'>
<c-shelf-empty v-if="showShelfEmpty"></c-shelf-empty>
<c-search-empty v-if="showSearchEmpty"></c-search-empty>
<c-empty v-else></c-empty>
</template>
<template v-else>
......@@ -17,7 +18,7 @@
</template>
</view>
<uni-load-more v-if='ableLoadMore' :status="loadMoreStatus.value" :contentText="loadMoreContentText"
iconType="snow"></uni-load-more>
iconType="circle"></uni-load-more>
</scroll-view>
</template>
......@@ -68,6 +69,10 @@
type: Boolean,
default: false
},
showSearchEmpty: {
type: Boolean,
default: false
},
/** 初始数据源 */
sources: {
type: Array,
......@@ -274,7 +279,7 @@
}
},
/** customeRequst 不会使用的接口*/
requestData() {
requestData(noLoading) {
if (this.needLogin && !this.userInfo) {
this.loading = false;
this.closeTrigger();
......@@ -299,7 +304,9 @@
header: this.header || {},
callback: (success, data) => {
this.loading = false;
if (!noLoading) {
this.closeTrigger();
}
if (success) {
let rows = data.records;
let total = data.total;
......
......@@ -116,7 +116,7 @@
},
ttLoging() {
var that = this;
var obj = tt.getLaunchOptionsSync()
var obj = wx.getLaunchOptionsSync()
var bookId = '';
var thirdParam = '';
var tips2 = '';
......@@ -132,23 +132,17 @@
this.$refs.select.open('center');
}
tt.login({
wx.login({
force: true,
success(res) {
login({
vedioId: bookId,
code: res.code,
anonymousCode: res.anonymousCode,
thirdParam: thirdParam
})
},
fail(res) {
// 登录授权失败
uni.navigateTo({
url: `/pages/warehouse/warehousetemp`,
})
},
fail(res) {},
});
}
......
......@@ -20,7 +20,7 @@
props: {
title: {
type: String,
default: "逸想小说阁"
default: "河狸小故事"
}
},
data() {
......
<template>
<view class="c-empty">
<image class='empty-image' :src='emptyImg'>
</image>
<slot></slot>
</view>
</template>
<script>
export default {
name: "c-shelf-empty",
data() {
return {
emptyImg: "https://mints-pkg.oss-cn-beijing.aliyuncs.com/pkg/img/bg_search_data.png"
}
},
}
</script>
<style lang="scss" scoped>
.c-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 400rpx;
.empty-image {
width: 324rpx;
height: 184rpx;
}
}
</style>
\ No newline at end of file
<template>
<view class="c-empty">
<view class="empty-title">
<image class='empty-image' :src='emptyImg'>
</image>
<!-- <view class="empty-title">
暂未添加到书架
</view>
</view> -->
<view class="empty-button" @click="goWareHouse">
去书
去书城看看
</view>
<slot></slot>
</view>
......@@ -15,8 +17,8 @@
name: "c-shelf-empty",
data() {
return {
};
emptyImg: "https://mints-pkg.oss-cn-beijing.aliyuncs.com/pkg/img/bg_book_data.png"
}
},
methods: {
goWareHouse() {
......@@ -36,20 +38,26 @@
align-items: center;
justify-content: center;
width: 100%;
height: 800rpx;
height: 400rpx;
.empty-title {
color: #999;
font-size: 26rpx;
margin-bottom: 40rpx;
margin-bottom: 20rpx;
}
.empty-image {
width: 240rpx;
height: 240rpx;
}
.empty-button {
margin-top: 30rpx;
font-size: 30rpx;
border: 1px solid #FECF02;
padding: 10rpx 40rpx;
border-radius: 30rpx;
color: #FECF02;
color: white;
background: linear-gradient(90deg, #F1413C, #FD6864);
}
}
</style>
\ No newline at end of file
<template>
<view>
<view style="z-index: 999;">
<uni-popup type="bottom" ref="coinPop" :maskClick="false" :isMaskClick="false">
<view style="position: relative;">
<view v-if="agreeFlag"
......@@ -17,23 +16,28 @@
<view class="body" style="width: 100%;height: 100%;background-color: white;">
<scroll-view scroll-y>
<view style="display: flex;flex-direction: column;align-items: flex-end;">
<view style="display: flex;flex-direction: column;">
<view style="display: flex;flex-direction: row;">
<view @click="handleAgree" style="margin-top: 12rpx;margin-right: 10rpx;">付费须知></view>
<view v-if="agreementDto != null" @click="handleUnsign"
style="margin-top: 12rpx;margin-left: 10rpx;">自动续费管理></view>
<view style="margin-top: 12rpx;margin-left: auto;display: flex;flex-direction: row;">
<view @click="handleAgree" style="margin-right: 10rpx;">付费须知></view>
<image @click="handleClickClose"
style="width: 30rpx;height: 30rpx;display: flex;align-items: right;margin-top: 20rpx;margin-right: 20rpx;margin-bottom: 10rpx;"
style="width: 30rpx;height: 30rpx;display: flex;align-items: right;margin-top: 20rpx;margin-left: auto;margin-right: 20rpx;margin-bottom: 10rpx;"
src="@/static/index/ic_quit_white.png"></image>
</view>
</view>
</view>
<view class="section">
<view class="pack-box">
<view class="pack-item"
:class="[{active: index==selectedIndex}]" v-for='(item, index) in vipList'
:key='index' @click="choosePack(item, index)">
<view class="pack-item" :class="[{active: index==selectedIndex}]"
v-for='(item, index) in vipList' :key='index' @click="choosePack(item, index)">
<view style="display: flex;flex-direction: column;align-items: center;">
<view class="price row">
{{item.firstPayPrice}}
{{item.firstPayPrice<=0 ? '免费试用' : item.firstPayPrice+'元'}}
</view>
<view class="name row" v-if="item.title!=null&&item.title!=''">
......@@ -58,6 +62,10 @@
</view>
</view>
<text class="trialStyle" v-show="hintText!=null&&hintText!=''">
{{hintText}}
</text>
<view style="display: flex;flex-direction: column;align-items: center;">
<view style="font-size: 24rpx;color: gray;margin-top: 16rpx;margin-bottom: 18rpx;">
订单中如有疑问,请在个人中心联系客服</view>
......@@ -75,7 +83,8 @@
<script>
import common from '@/mixins/common';
import {
message
message,
navigateTo
} from '@/utils/fun';
export default {
name: 'coinPopup',
......@@ -100,6 +109,8 @@
selectedIndex: 0,
agreeFlag: false,
userBean: {},
agreementDto: null,
hintText: '',
os: 'android',
titleText: '超多精彩小说一键解锁',
showClone: false
......@@ -115,12 +126,12 @@
let that = this;
this.$refs.coinPop.open('bottom');
if (tt.getSystemInfoSync().platform === 'ios') {
if (wx.getSystemInfoSync().platform === 'ios') {
this.os = 'ios';
}
this.post({
url: '/vip/getVipProducts',
url: '/vip/getVipProducts/cyc',
data: {
bookId: that.vedioId
},
......@@ -130,7 +141,7 @@
}) => {
this.vipList = data.list;
if (data.list != null) {
// this.selectedIndex = data.list[0].activityType;
this.hintText = this.vipList[0].trailRemark;
for (let i = 0; i < data.list.length; i++) {
if (data.list[i].activityType == 1) {
this.selectedIndex = i;
......@@ -142,15 +153,28 @@
});
this.post({
url: '/user/baseMsg',
url: '/vip/getOrderList',
showLoading: false,
success: ({
data
}) => {
this.userBean = data;
console.log("agreement=", data.agreement);
if (data.agreement == undefined) {
console.log("agreement=22222");
this.agreementDto = null;
} else {
this.agreementDto = data.agreement;
}
}
});
},
handleUnsign() {
if (this.agreementDto) {
let params = JSON.stringify(this.agreementDto)
navigateTo(`/pagesA/unsign/unsign?params=` + params)
}
},
handleAgree() {
this.agreeFlag = true
},
......@@ -165,96 +189,82 @@
},
choosePack(item, index) {
this.selectedIndex = index;
if (this.vipList[this.selectedIndex].trailRemark != null) {
this.hintText = this.vipList[this.selectedIndex].trailRemark;
} else {
this.hintText = '';
}
this.handlePay();
},
handlePay() {
if (this.os == 'ios') {
message.notify('iOS暂不支持购买');
return
}
let that = this;
let vipBean = this.vipList[this.selectedIndex];
// 抖音支付
var vipBean = this.vipList[this.selectedIndex];
if (this.os == 'ios') {
message.notify('暂不支持ios系统~');
} else {
this.post({
url: '/vip/getVipPayParams/douyin',
url: '/vip/getVipPayParams/wechat',
data: {
bookId: that.vedioId,
os: that.os,
pid: vipBean.pid
pid: vipBean.pid,
payChannel: 'WEIXIN'
},
showLoading: true,
success: ({
data
}) => {
that.ttPrePay(data, vipBean.largeType);
}
});
},
ttPrePay(ttData, largeType) {
if (!tt.canIUse('requestOrder')) {
message.notify('请升级抖音APP版本.');
return
if (vipBean.firstPayPrice == 0) {
//签约
that.wxSign(data, vipBean.largeType);
} else {
//普通支付
that.wxPay(data, vipBean.largeType);
}
uni.showLoading({
title: '加载中...'
}
});
}
},
wxPay(wxData, largeType) {
let wxParams = wxData.params;
let that = this;
tt.requestOrder({
data: ttData.params.data,
byteAuthorization: ttData.params.byteAuthorization,
// 发起微信支付
wx.requestPayment({
timeStamp: wxParams.timeStamp,
nonceStr: wxParams.nonceStr,
package: wxParams.packageStr,
signType: wxParams.signType,
paySign: wxParams.paySign,
success(res) {
that.ttPay(largeType, res.orderId, ttData);
that.queryOrderStatus(largeType, wxData.tidStr);
},
fail(res) {
uni.hideLoading();
console.log('ttPrePay', res.errMsg);
// message.notify(res.errMsg);
},
});
fail(res) {}
})
},
ttPay(largeType, oid, ttData) {
uni.hideLoading();
if (!tt.canIUse('getOrderPayment')) {
message.notify('请升级抖音APP版本!');
return
}
wxSign(wxData, largeType) {
let wxParams = wxData.params;
let that = this;
if (this.os == 'ios') {
if (!tt.canIUse('getOrderPayment.object.imId')) {
message.notify('请升级抖音APP版本~');
return
}
tt.getOrderPayment({
orderId: oid,
imId: ttData.imId,
// 发起微信签约
wx.navigateToMiniProgram({
appId: "wxbd687630cd02ce1d",
path: 'pages/index/index',
extraData: wxData.params,
success(res) {
that.queryOrderStatus(largeType, ttData.tidStr);
},
fail(res) {
console.log('ios pay', res.errMsg);
// message.notify(res.errMsg);
},
});
console.log("wxSign suc=", res);
if (res.return_code == 'SUCCESS') {
console.log("wxSign suc1111");
// 成功跳转到签约小程序
that.queryOrderStatus(largeType, wxData.tidStr);
} else {
tt.getOrderPayment({
orderId: oid,
success(res) {
that.queryOrderStatus(largeType, ttData.tidStr);
// 签约失败
console.log("wxSign fail22222");
}
},
fail(res) {
console.log('android pay', res.errMsg);
// message.notify(res.errMsg);
},
});
// 未成功跳转到签约小程序
console.log("wxSign fail=3333", res);
}
})
},
queryOrderStatus(largeType, tid) {
let that = this;
......@@ -386,4 +396,16 @@
}
}
}
.trialStyle {
display: flex;
align-items: center;
font-size: 30rpx;
color: darkgray;
margin-left: 20rpx;
margin-right: 20rpx;
word-wrap: break-word;
word-break: break-all;
white-space: pre-line;
}
</style>
\ No newline at end of file
This diff is collapsed.
......@@ -5,8 +5,9 @@
<image @click="onClose" style="width: 50rpx; height: 50rpx;margin-left:auto;margin-right: 30rpx;
margin-bottom: 30rpx;" src="https://mints-web.oss-cn-beijing.aliyuncs.com/images/ic_close_white.png"></image>
<view class="content">
<button class="button1" type="default" size="default" @click="tapMakePhoneCall">客服电话</button>
<button class="button2" open-type="im" data-im-id="93264117800">客服在线</button>
<button class="button1" type="default" size="default"
@click="tapMakePhoneCall">客服电话:400-096-9950</button>
<!-- <button class="button2" open-type="im" data-im-id="93264117800">客服在线</button> -->
</view>
</view>
</uni-popup>
......@@ -14,6 +15,8 @@
</template>
<script>
// import uniPopuo from 'uniPopuo'
export default {
name: 'kefuPopup',
props: {
......@@ -36,8 +39,8 @@
this.$emit('close');
},
tapMakePhoneCall() {
let that=this
tt.makePhoneCall({
let that = this
wx.makePhoneCall({
phoneNumber: "4000969950",
success(res) {
// 调用成功 makePhoneCall:ok
......
<template>
<view class="c-flex_row c-aligns_center c-justify_between read-time-count-row">
<view class="c-flex_column c-aligns_center">
<view class="c-flex_row c-aligns_center">
<!-- <view class="label">
<view class="title">
今日阅读时间
今日<br>已读
</view>
<view class="value" v-if='count.count'>
<view class="count" v-if='count.hour'>
<view class="count-value">{{count.hour}}</view>
</view> -->
<image class="labelimg" src="../../static/images/readtext.png"></image>
<!-- <view class="value" v-if='count.count'> -->
<view class="value">
<view class="count">
<view class="count-value">{{count.hour ?count.hour:'00'}}</view>
<view class="count-unit">小时</view>
</view>
<view class="count" v-if='count.minute'>
<view class="count-value">{{count.minute}}</view>
<view class="count-unit"></view>
<view class="count">
<view class="count-value">{{count.minute?count.minute:'00'}}</view>
<view class="count-unit"></view>
</view>
<view class="count" v-if='count.second'>
<view class="count-value">{{count.second}}</view>
<view class="count">
<view class="count-value">{{count.second?count.second:'00'}}</view>
<view class="count-unit"></view>
</view>
</view>
<view class="value" v-else>
<!-- <view class="value" v-else>
<view class="count">
<view class="count-value" style="color: #ffffff00;">
0
......@@ -27,7 +31,7 @@
尚未开始
</view>
</view>
</view>
</view> -->
</view>
<view class="c-flex_column c-aligns_center">
<slot name="right"></slot>
......@@ -71,38 +75,46 @@
<style lang="scss">
.read-time-count-row {
padding: 20rpx 40rpx;
padding: 20rpx;
padding-left: 0;
.title {
font-size: 28rpx;
color: #333;
margin-bottom: 20rpx;
.labelimg {
margin-top: 10rpx;
margin-right: 20rpx;
width: 65rpx;
height: 70rpx;
}
.value {
display: flex;
flex-direction: row;
align-items: center;
.count {
display: flex;
flex-direction: row;
margin-right: 10rpx;
position: relative;
margin-right: 15rpx;
font-size: 24rpx;
color: #333;
background-color: #FEF3F3;
border-radius: 10rpx;
width: 90rpx;
height: 90rpx;
color: #383B3D;
.count-value {
color: #007aff;
font-size: 38rpx;
position: absolute;
top: 42%;
left: 50%;
transform: translate(-50%, -50%);
color: #383B3D;
font-size: 46rpx;
font-weight: 700;
height: 40rpx;
line-height: 40rpx;
}
.count-unit {
margin-left: 8rpx;
height: 40rpx;
line-height: 40rpx;
font-size: 20rpx;
position: absolute;
left: 50%;
transform: translate(-50%);
bottom: 4rpx;
}
}
}
......
<template>
<view class="recommendlist">
<view class="booklabel">
<view class="title">{{title}}</view>
<view class="flex">
<image class="img" src="@/static/images/change.png"></image>
<view class="change" @click="refreshList">换一换</view>
</view>
</view>
<view class="rowitem" v-if="listType==0">
<!-- 猜你喜欢 -->
<book-list-item2 class="item" v-for='(item, index) in dataList' :key='index' :item='item'
@tapItem='tapItem($event, index)'>
</book-list-item2>
</view>
<view class="columnitem" v-else-if="listType==1">
<!-- 热门推荐-首页 -->
<book-list-item :item='dataList[0]' :showClose='false' @tapItem='tapItem($event, index)'>
</book-list-item>
<view class="rowitem">
<book-list-item2 class="item" :item='item' v-if="index!=0" v-for='(item, index) in dataList'
:key='index' @tapItem='tapItem($event, index)'>
</book-list-item2>
</view>
</view>
<view class="rowitem" v-else-if="listType==2">
<!-- 新书推荐 -->
<book-list-item3 class="item2" v-for='(item, index) in dataList' :key='index' :item='item'
:showClose='false' @tapItem='tapItem($event, index)'>
</book-list-item3>
</view>
<view class="columnitem" v-else-if="listType==3">
<!-- 热门推荐-搜索页 -->
<book-list-item v-for='(item, index) in dataList' :key='index' :item='item'
@tapItem='tapItem($event, index)' :showClose='false'>
</book-list-item>
</view>
</view>
</template>
<script>
import common from '@/mixins/common';
import {
getRecommendV1,
getArticleLike
} from "../../common/services/index.js"
import {
gotoBookContentPage
} from '../../common/services/page-route.js';
import BookshelfBookItem from '../../common/models/BookshelfBookItem.js';
import BookListItem from "@/components/book-list-item/book-list-item.vue";
import BookListItem2 from "@/components/book-list-item2/book-list-item2.vue";
import BookListItem3 from "@/components/book-list-item3/book-list-item3.vue";
export default {
mixins: [common],
components: {
BookListItem,
BookListItem2,
BookListItem3
},
props: {
listType: {
type: Number,
default: 0
}
},
data: function() {
return {
dataList: [],
title: '猜你喜欢',
flag: 'hot'
}
},
mounted() {
if (this.listType == 0) {
this.flag = 'like'
this.title = '猜你喜欢'
} else if (this.listType == 1 || this.listType == 3) {
this.flag = 'hot'
this.title = '热门推荐'
} else if (this.listType == 2) {
this.flag = 'newbook'
this.title = '新书推荐'
}
},
methods: {
refreshList() {
if (this.listType == 0) {
getArticleLike(8, (success, data) => {
if (success) {
this.changeData(data)
}
})
} else if (this.listType == 1) {
getRecommendV1(this.flag, 5, (success, data) => {
if (success) {
this.changeData(data)
}
})
} else if (this.listType == 2) {
getRecommendV1(this.flag, 8, (success, data) => {
if (success) {
this.changeData(data)
}
})
} else if (this.listType == 3) {
getRecommendV1(this.flag, 8, (success, data) => {
if (success) {
this.changeData(data)
}
})
}
},
changeData(e) {
this.dataList = e.records.map(item => {
return new BookshelfBookItem(item)
})
},
tapItem(e, index) {
gotoBookContentPage(e.detail.data.id, e.detail.data.shortis)
},
}
}
</script>
<style lang="scss" scoped>
.recommendlist {
display: flex;
flex-direction: column;
border-radius: 20rpx;
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.1);
background-color: white;
margin: 30rpx;
margin-bottom: 0;
.booklabel {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 100rpx;
line-height: 100rpx;
padding: 0 20rpx;
.title {
font-weight: 500;
font-size: 34rpx;
color: #383B3D;
}
.img {
margin-right: 10rpx;
width: 30rpx;
height: 26rpx;
}
.change {
font-weight: 400;
font-size: 24rpx;
color: #A5A5AD;
}
}
.columnitem {
display: flex;
flex-direction: column;
}
.rowitem {
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding-left: 20rpx;
.item2 {
width: 47%;
margin-bottom: 20rpx;
margin-right: 20rpx;
}
.item:last-child {
margin-right: 0;
}
.item {
width: 22%;
margin-bottom: 20rpx;
margin-right: 20rpx;
}
.item:last-child {
// margin-bottom: 0;
margin-right: 0;
}
}
}
</style>
\ No newline at end of file
<!-- 底部弹窗(分享) -->
<template>
<view v-if="showPopup" class="uni-popup" @touchmove.stop.prevent="clear">
<uni-transition :mode-class="['fade']" :styles="maskClass" :duration="duration" :show="showTrans" @click="onTap" />
<uni-transition :mode-class="ani" :styles="transClass" :duration="duration" :show="showTrans" @click="onTap">
<view class="uni-popup__wrapper-box" @click.stop="clear">
<slot />
</view>
</uni-transition>
</view>
</template>
<script>
/**
* PopUp 弹出层
* @description 弹出层组件,为了解决遮罩弹层的问题
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} type = [top|center|bottom] 弹出方式
* @value top 顶部弹出
* @value center 中间弹出
* @value bottom 底部弹出
* @property {Boolean} animation = [ture|false] 是否开启动画
* @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗
* @event {Function} change 打开关闭弹窗触发,e={show: false}
*/
export default {
name: 'UniPopup',
props: {
// 开启动画
animation: {
type: Boolean,
default: true
},
// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
type: {
type: String,
default: 'center'
},
// maskClick
maskClick: {
type: Boolean,
default: true
}
},
data() {
return {
duration: 300,
ani: [],
showPopup: false,
showTrans: false,
maskClass: {
'position': 'fixed',
'bottom': 0,
'top': 0,
'left': 0,
'right': 0,
'backgroundColor': 'rgba(0, 0, 0, 0.4)'
},
transClass: {
'position': 'fixed',
'left': 0,
'right': 0,
}
}
},
watch: {
type: {
handler: function(newVal) {
switch (this.type) {
case 'top':
this.ani = ['slide-top']
this.transClass = {
'position': 'fixed',
'left': 0,
'right': 0,
}
break
case 'bottom':
this.ani = ['slide-bottom']
this.transClass = {
'position': 'fixed',
'left': 0,
'right': 0,
'bottom': 0
}
break
case 'center':
this.ani = ['zoom-out', 'fade']
this.transClass = {
'position': 'fixed',
/* #ifndef APP-NVUE */
'display': 'flex',
'flexDirection': 'column',
/* #endif */
'bottom': 0,
'left': 0,
'right': 0,
'top': 0,
'justifyContent': 'center',
'alignItems': 'center'
}
break
}
},
immediate: true
}
},
created() {
if (this.animation) {
this.duration = 300
} else {
this.duration = 0
}
},
methods: {
clear(e) {
// TODO nvue 取消冒泡
e.stopPropagation()
},
open() {
this.showPopup = true
this.$nextTick(() => {
clearTimeout(this.timer)
this.timer = setTimeout(() => {
this.showTrans = true
}, 50);
})
this.$emit('change', {
show: true
})
},
close(type) {
this.showTrans = false
this.$nextTick(() => {
clearTimeout(this.timer)
this.timer = setTimeout(() => {
this.$emit('change', {
show: false
})
this.showPopup = false
}, 300)
})
},
onTap() {
if (!this.maskClick) return
this.close()
}
}
}
</script>
<style lang="scss" scoped>
.uni-popup {
position: fixed;
/* #ifdef H5 */
top: var(--window-top);
/* #endif */
/* #ifndef H5 */
top: 0;
/* #endif */
bottom: 0;
left: 0;
right: 0;
/* #ifndef APP-NVUE */
z-index: 99999999999;
/* #endif */
}
.uni-popup__mask {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: $uni-bg-color-mask;
opacity: 0;
}
.mask-ani {
transition-property: opacity;
transition-duration: 0.2s;
}
.uni-top-mask {
opacity: 1;
}
.uni-bottom-mask {
opacity: 1;
}
.uni-center-mask {
opacity: 1;
}
.uni-popup__wrapper {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: absolute;
}
.top {
top: 0;
left: 0;
right: 0;
transform: translateY(-500px);
}
.bottom {
bottom: 0;
left: 0;
right: 0;
transform: translateY(500px);
}
.center {
/* #ifndef APP-NVUE */
display: flex;
flex-direction: column;
/* #endif */
bottom: 0;
left: 0;
right: 0;
top: 0;
justify-content: center;
align-items: center;
transform: scale(1.2);
opacity: 0;
}
.uni-popup__wrapper-box {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: relative;
}
.content-ani {
// transition: transform 0.3s;
transition-property: transform, opacity;
transition-duration: 0.2s;
}
.uni-top-content {
transform: translateY(0);
}
.uni-bottom-content {
transform: translateY(0);
}
.uni-center-content {
transform: scale(1);
opacity: 1;
}
</style>
<template>
<scroll-view class="bar-box" scroll-x id='box' :scroll-into-view="scrollId">
<view v-if='showEmpty' class="tab-item">
<!-- <view v-if='showEmpty' class="tab-item">
<view class="title">
暂无分类数据
</view>
</view>
<view v-else :id="'item_'+index" class="tab-item" :class="{'tab-item-selected': item.selected}"
</view> -->
<view :id="'item_'+index" class="tab-item" :class="{'tab-item-selected': item.selected}"
v-for="(item, index) in tabs" :key='item.name' @click="tapTab(index)">
<view class="title">
{{item.name}}
......@@ -129,6 +129,7 @@
<style lang="scss">
.bar-box {
margin: 20rpx 0;
white-space: nowrap;
padding: 0 20rpx;
width: calc(100% - 40rpx);
......@@ -139,10 +140,12 @@
flex-direction: column;
align-items: center;
justify-content: center;
padding: 25rpx 20rpx;
border-radius: 30rpx;
padding: 8rpx 16rpx;
font-size: 30rpx;
background: transparent;
color: #888;
background: #EEEEEE;
color: #6B6B6B;
margin: 0 16rpx;
.title {
min-width: 80rpx;
......@@ -151,16 +154,15 @@
}
.tab-item:first-child {
padding-left: 0;
margin-left: 0;
}
.tab-item:last-child {
padding-right: 0;
margin-right: 0;
}
.tab-item-selected {
font-size: 36rpx;
font-weight: 700;
color: #333
background: #F1413C;
color: white;
}
</style>
\ No newline at end of file
<template>
<view>
<c-list ref='list' flag='warehouse' method="POST" :height="height" url='/book/articleList/' :param="requestParam"
@change='changeData'>
<c-list ref='list' flag='warehouse' method="POST" :height="height" url='/book/articleList/'
:param="requestParam" @change='changeData'>
<book-list-item v-for='(item, index) in dataList' :key='index' :item='item' :showClose='false'
@tapItem='tapItem($event, index)' @close='tapClose($event, index)'>
</book-list-item>
......@@ -17,8 +17,12 @@
isEmpty
} from '../../../common/utils/util'
import WarehouseBookItem from '../models/WarehouseBookItem.js';
import CList from "@/components/c-list/c-list.vue";
export default {
components: {},
components: {
CList
},
props: {
height: {
type: Number,
......@@ -54,7 +58,7 @@
this.$nextTick(() => {
let ref = this.$refs.list;
if (ref) {
ref.onPullRefreshing();
ref.requestData(1);
}
})
},
......@@ -64,7 +68,7 @@
})
},
tapItem(e, index) {
gotoBookContentPage(e.detail.data.id)
gotoBookContentPage(e.detail.data.id, e.detail.data.shortis)
},
tapClose(e, index) {
// TODO 仓库点击关闭按钮,弹窗选择关闭原因
......
......@@ -10,14 +10,7 @@ function getCategorys(callback) {
})
}
function getFirstShow(callback) {
apiPOST({
url: "/book/firstArticle",
callback
})
}
module.exports = {
getCategorys,
getFirstShow
getCategorys
}
\ No newline at end of file
<template>
<z-paging>
<c-navi id='navi'></c-navi>
<book-search-box id='search'></book-search-box>
<scroll-view scroll-y style="height: 100%;">
<CategoryBar id='category' :range='categorys' :current='currentIndex' @change='changeCategory'
@ready='readyCategory'></CategoryBar>
<view :style="[listStyle]" v-if='showEmpty'>
......@@ -12,25 +10,24 @@
@change="changeSwiper">
<swiper-item v-for='(item, index) in categorys' :key='index'>
<WarehouseList :ref="`bookList${index}`" :category='item' :height='listHeight'></WarehouseList>
<!-- <WarehouseList ref="bookList" :category='item' :height='listHeight'></WarehouseList> -->
</swiper-item>
</swiper>
</view>
<c-login></c-login>
</z-paging>
<view style="height: 20rpx;"></view>
</scroll-view>
</template>
<script>
import CategoryBar from "./components/category-bar.vue";
import WarehouseList from "./components/warehouse-list.vue";
import CEmpty from "@/components/c-empty/c-empty.vue";
import SystemInfoMixin from "../../common/mixins/system-info-mixin.js";
import Category from "./models/Category.js";
import {
gotoBookContentPage
} from '../../common/services/page-route'
import {
getCategorys,
getFirstShow
getCategorys
} from "./services/index.js"
import {
isEmpty
......@@ -42,7 +39,8 @@
mixins: [SystemInfoMixin],
components: {
CategoryBar,
WarehouseList
WarehouseList,
CEmpty
},
data() {
return {
......@@ -51,8 +49,9 @@
currentIndex: 0,
};
},
onLoad(options) {
onLoad(options) {},
onReady() {
this.getCategoryData()
},
computed: {
showEmpty: function() {
......@@ -60,7 +59,7 @@
},
listStyle: function() {
return {
height: `${this.listHeight}px`
height: `${this.listHeight}px`,
}
},
categroyChange: function() {
......@@ -79,54 +78,21 @@
handler: function(n, o) {
setTimeout(() => {
this.$refs[`bookList${n.currentIndex}`][0].initRefresh();
}, 500)
// this.$nextTick(() => {
// // this.$refs[`bookList${n.currentIndex}`][0].initRefresh();
// let ref = this.$refs.bookList;
// if (ref) {
// ref[n.currentIndex].initRefresh();
// }
// })
}, 300)
},
deep: true
}
},
methods: {
show() {
this.getFirstShowData();
this.getCategoryData();
if (wx.setVisualEffectOnCapture) {
wx.setVisualEffectOnCapture({
visualEffect: 'hidden',
success: (res) => {
},
})
}
},
hide() {
},
readyCategory() {
setTimeout(() => {
this.initHeight()
}, 300)
},
getFirstShowData(){
getFirstShow((success, data) => {
if (success) {
setTimeout(() => {
// 匹配用户直接跳转小说
if (data.articleMsg != null) {
gotoBookContentPage(data.articleMsg.id);
}
}, 800);
}
})
},
getCategoryData() {
getCategorys((success, data) => {
if (success) {
......@@ -151,7 +117,9 @@
query.exec((res) => {
let result = 0;
res.forEach(item => {
if (item) {
result = result + item.height;
}
})
this.listHeight = this.windowHeight - result - (this.windowHeight * 0.1);
})
......
<template>
<view style="padding-top: 50rpx;">
<profile-header :userInfo='userInfo'></profile-header>
<CategoryBar id='category' :range='categorys' :current='currentIndex' @change='changeCategory'
@ready='readyCategory'></CategoryBar>
<view :style="[listStyle]" v-if='showEmpty'>
<c-empty emptyTitle="暂无数据"></c-empty>
</view>
<view :style="[listStyle]" v-else>
<swiper :style="[listStyle]" :indicator-dots="false" :autoplay="false" :current="currentIndex"
@change="changeSwiper">
<swiper-item v-for='(item, index) in categorys' :key='index'>
<WarehouseList ref='bookList' :category='item' :height='listHeight'></WarehouseList>
</swiper-item>
</swiper>
</view>
<c-login></c-login>
</view>
</template>
<script>
import ProfileHeader from "./components/profile-headertemp.vue";
import {
watchUserInfoChange,
refreshUserInfo
} from "../../common/services/userServices.js"
import CategoryBar from "./components/category-bar.vue";
import WarehouseList from "./components/warehouse-list.vue";
import SystemInfoMixin from "../../common/mixins/system-info-mixin.js";
import Category from "./models/Category.js";
import {
getCategorys
} from "./services/index.js"
import {
isEmpty
} from "../../common/utils/util";
import {
readStorage,
saveStorage
} from '../../common/utils/storageUtil';
export default {
mixins: [SystemInfoMixin],
components: {
CategoryBar,
ProfileHeader,
WarehouseList
},
data() {
return {
userInfo: null,
listHeight: 0,
categorys: [],
currentIndex: 0
};
},
onLoad() {
this.getCategoryData();
watchUserInfoChange((info) => {
this.userInfo = info.userInfo
}, this);
},
onShow() {
this.refreshUserData();
},
computed: {
showEmpty: function() {
return isEmpty(this.categorys);
},
listStyle: function() {
return {
height: `${this.listHeight}px`
}
},
categroyChange: function() {
const {
categorys,
currentIndex
} = this;
return {
categorys,
currentIndex
}
}
},
watch: {
categroyChange: {
handler: function(n, o) {
this.$nextTick(() => {
let ref = this.$refs.bookList;
if (ref) {
ref[n.currentIndex].initRefresh();
}
})
},
deep: true
}
},
methods: {
readyCategory() {
setTimeout(() => {
this.initHeight()
}, 300)
},
getCategoryData() {
getCategorys((success, data) => {
if (success) {
let result = data ? data.map(item => {
return new Category(item)
}).sort((a, b) => {
return a.sort - b.sort
}) : [];
result.unshift(new Category({
name: "全部",
id: ""
}))
this.categorys = result;
}
})
},
initHeight() {
const query = uni.createSelectorQuery().in(this);
// query.select("#navi").boundingClientRect();
// query.select("#search").boundingClientRect();
query.select("#category").boundingClientRect();
query.exec((res) => {
let result = 0;
res.forEach(item => {
result = result + item.height;
})
this.listHeight = this.windowHeight - result;
})
},
changeCategory(e) {
this.changeCurrent(e.index);
},
changeSwiper(e) {
this.changeCurrent(e.detail.current);
},
changeCurrent(index) {
if (index != this.currentIndex) {
this.currentIndex = index;
}
},
refreshUserData() {
if (this.userInfo) {
refreshUserInfo();
}
}
}
}
</script>
<style lang="scss">
.name {
font-size: 34rpx;
font-weight: 700;
}
</style>
\ No newline at end of file
This diff is collapsed.
<template>
<view class="read" id="read">
<view class="read-content" :class="'read-content'+index" :style="elStyle" v-for="(item,index) in list"
:key="index" @click="toClick">
{{item.content}}
</view>
<!-- <view class="read-content" :style="elStyle" @click="toNext">{{content}}</view>
<view class="read-content-next" :style="elStyle">{{contentNext}}</view> -->
<view class="top-info" v-if="setShow">
<view class="top-info-item">
<text text="上一章" block align="center" v-if="partInfo.previousPartNum != -1"
@tap.native.stop="toPrePart">上一章
</text>
</view>
<view class="top-info-item">
<!-- <u-button type="default" size="mini" plain shape="circle" text="目录" @tap.native.stop="toMenu">
</u-button> -->
<text text="目录" align="center" @tap.native.stop="toMenu">目录</text>
</view>
<view class="top-info-item">
<text text="下一章" align="center" v-if="partInfo.nextPartNum != -1" @tap.native.stop="toNextPart">下一章
</text>
</view>
</view>
<view class="bottom-info" v-if="setShow">
<view class="bottom-info-item">
<text text="设置" prefixIcon="setting" size="17" lineHeight="20" :iconStyle="{fontSize: '20px'}"
align="center" @tap.native.stop="toSet">设置</text>
</view>
<view class="bottom-info-item">
<text text="|" align="center" size="17" color="#dadada">|</text>
</view>
<view class="bottom-info-item">
<text text="返回书城" prefixIcon="home" size="17" lineHeight="20" align="center"
:iconStyle="{fontSize: '20px'}" @tap.native.stop="toHome">返回书城</text>
</view>
</view>
<view class="bottom-info font-style" v-if="setStyleShow">
<view class="item">
<view class="item-title">
字号
</view>
<view class="item-cont">
<view class="item-cont-item" @click="setFontSize(1)">
-
</view>
<view class="item-cont-item" @click="setFontSize(2)">
+
</view>
</view>
</view>
<view class="item">
<view class="item-title">
背景
</view>
<view class="item-cont">
<view class="item-cont-item" :class="curColor==item?'active':''" @click="setBgColor(item)"
v-for="(item,index) in colors" :key="index" :style="'background-color:'+item+';'">
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import datas from "./data.js"
export default {
data() {
return {
content: "22222",
contentPre: "11111",
contentNext: "3333",
list: [],
colors: [
"#F1FAFA",
"#e8ffe8",
"#e8e8ff",
"#8080c0",
],
curColor: "#F1FAFA",
setShow: false,
setStyleShow: false,
isStart: true,
isEnd: false,
width: 0,
height: 0,
start: 0,
end: 0,
length: 0,
heightOffset: 16,
styleObj: {
fontSize: 16,
lineHeight: 1
},
elStyle: "",
partInfo: {
previousPartNum: 1,
nextPartNum: 1
}
};
},
mounted() {
this.$nextTick(() => {
this.init()
})
},
methods: {
setFontSize(flag) {
//-
if (flag == 1) {
if (this.styleObj.fontSize < 10) {
return;
}
this.styleObj.fontSize -= 1;
} else { //+
if (this.styleObj.fontSize > 40) {
return;
}
this.styleObj.fontSize += 1;
}
this.init()
},
setBgColor(color) {
this.curColor = color;
this.setStyle()
},
toSet() {
console.log("设置")
this.setStyleShow = true;
this.setShow = false;
},
toPrePart() {
console.log("上一章节")
},
toNextPart() {
console.log("下一章节")
},
toHome() {
console.log("返回首页")
},
toMenu() {
// this.$refs.parts.open();
console.log("显示目录")
},
toClick(e) {
if (this.setStyleShow || this.setShow) {
this.setStyleShow = false;
this.setShow = false;
return;
}
const width = this.width;
const x = e.detail.x;
if (x < width / 3) {
this.toPre()
} else if (x > (width / 3) * 2) {
this.toNext()
} else {
this.setShow = !this.setShow;
}
},
toPre() {
if (this.isStart) {
uni.showToast({
title: "已经是第一页了",
icon: "none"
})
return;
}
this.start -= this.length;
this.setContent()
},
toNext() {
if (this.isEnd) {
uni.showToast({
title: "已经是最后一页了",
icon: "none"
})
return;
}
this.start += this.length;
this.setContent()
// console.log(this.start, this.list)
},
init() {
console.log(111111111, this.content)
const query = uni.createSelectorQuery().in(this);
const el = query.select("#read").boundingClientRect(data => {
console.log(11111, data)
const width = data.width - 20;
const height = data.height - 20;
this.width = width;
this.height = height;
let lineHeight = ((this.styleObj.fontSize) * this.styleObj.lineHeight) + this.heightOffset;
let lineNum = parseInt(height / lineHeight) - 1;
let fonts = parseInt(width / (this.styleObj.fontSize));
let allFonts = lineNum * fonts;
this.length = allFonts;
console.log("--->>>", allFonts, fonts, lineNum, height, lineHeight)
this.setStyle()
this.setContent()
}).exec();
},
setContent() {
this.list = []
let cont0 = "";
let cont1 = datas.substr(this.start, this.length);
let cont2 = datas.substr(this.start + this.length, this.length);
if (cont1.length < this.length) {
this.isEnd = true;
} else {
this.isEnd = false;
}
if (this.start != 0) {
this.isStart = false;
cont0 = datas.substr(this.start - this.length, this.length)
} else {
this.isStart = true;
}
this.list.push({
index: 0,
content: cont0
})
this.list.push({
index: 1,
content: cont1
})
this.list.push({
index: 2,
content: cont2
})
},
setStyle() {
let fontSize = this.styleObj.fontSize;
let lineHeight = (((this.styleObj.fontSize) * this.styleObj.lineHeight) + this.heightOffset);
this.elStyle = `font-size: ${fontSize}px;line-height: ${lineHeight}px;background-color:${this.curColor};`;
// console.log(1,this.elStyle)
}
},
}
</script>
<style lang="scss">
page {
width: 100%;
height: 100%;
}
</style>
<style lang="scss" scoped>
* {
box-sizing: border-box;
}
.read {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
box-sizing: border-box;
&-content {
padding: 20rpx;
width: 100%;
height: 100%;
box-sizing: border-box;
position: absolute;
background-color: #f5ebdc;
}
&-content0 {
z-index: 1;
}
&-content1 {
z-index: 20;
}
&-content2 {
z-index: 10;
}
}
.top-info {
position: fixed;
top: 0rpx;
left: 0rpx;
display: flex;
background-color: #fff;
height: 90rpx;
border-bottom: 1px solid #dadada;
width: 100%;
z-index: 999;
&-item {
padding: 10rpx 0rpx;
flex: 1;
text-align: center;
}
}
.bottom-info {
position: absolute;
box-sizing: border-box;
bottom: 0rpx;
left: 0rpx;
display: flex;
background-color: #fff;
height: 210rpx;
padding: 50rpx 30rpx;
border-top: 1px solid #dadada;
width: 100%;
z-index: 999;
&-item {
padding: 10rpx 0rpx;
flex: 1;
text-align: center;
}
}
.font-style {
height: 400rpx;
flex-direction: column;
}
.item {
display: flex;
padding: 20rpx;
height: 150rpx;
line-height: 110rpx;
&-title {
width: 140rpx;
}
&-cont {
width: calc(100% - 140rpx);
display: flex;
&-item {
flex: 1;
background-color: #d8ebf5;
height: 100rpx;
border-radius: 60rpx;
margin-right: 30rpx;
text-align: center;
font-size: 60rpx;
line-height: 90rpx;
color: #03a9f4;
}
.active {
border: 1px solid #03a9f4;
}
}
}
</style>
......@@ -80,7 +80,6 @@ export default {
// navigateTo('user/login?redirect=' + encodeURIComponent(redirect));
},
logout() {
uni.removeStorageSync('token');
},
post(options) {
options = Object.assign({
......
......@@ -261,7 +261,7 @@
this.bookData = new BookDetail(data);
// console.log('bookData=' + JSON.stringify(this.bookData));
}
}, 1000)
}, 100)
})
},
paySuccess() {
......
<template>
<view>
<c-login></c-login>
</view>
</template>
<script>
export default {
data() {
return {
bookId: null,
bookCoverData: null
};
},
onReady() {
const eventChannel = this.getOpenerEventChannel();
eventChannel.on("openBookCoverPage", (info) => {
this.bookId = info.bookId
})
},
watch: {
bookId: function(n) {
if (n) {
this.$nextTick(() => {
uni.startPullDownRefresh({
})
})
}
}
},
onPullDownRefresh() {
this.refreshBookCoverData(this.bookId)
},
methods: {
refreshBookCoverData(bookId) {
}
}
}
</script>
<style lang="scss">
</style>
\ No newline at end of file
<template>
</template>
<script>
</script>
<style>
</style>
\ No newline at end of file
<template>
<view :style="[bgStyle]">
<c-empty v-if='showEmpty'></c-empty>
<template v-else>
<detail-content ref="content" :detail='bookData' @tabVip2="tapVipPop"
@changeCurrent="changeCurrent"></detail-content>
<detail-bottom :detail='bookData' :userInfo='userInfo' @tapBottomItem='tapBottomItem'></detail-bottom>
<setting-pop :show='showSetting' @close='closePop'></setting-pop>
<catalogue-pop :detail='bookData' :show='showCatalogue' @close='closeCataPop' :current="current"
@tabVip='tapVipPop'></catalogue-pop>
<!-- <vip-pop v-if="bookData.isUnlock==0 && !isVip()" :show='showVip' @close='closeVipPop'></vip-pop>
<bean-pop v-if="bookData.isUnlock==0 && userInfo.bookLegumes<bookData.bookLegumes" :show='showBean'
@close='closeBeanPop'></bean-pop> -->
<recommend-pop :show='showRecommend' @close='closeRecommendPop' :bookId="bookId"></recommend-pop>
<coin-popup v-if="bookData.isUnlock==0 && !isVip()" :show="showVip" @close="closeVipPop"
:vedioId="bookData.id">
</coin-popup>
</template>
</view>
</template>
<script>
import {
isEmpty
} from "../../../common/utils/util.js";
import BookDetail from "./models/BookDetail.js";
import {
getBookDetailData,
addReadRecord
} from "./services/index.js"
import {
collectionBook
} from "../../../common/services/index.js"
import DetailWarn from "./components/detail-warn.vue";
import DetailThumb from "./components/detail-thumb.vue";
import DetailContent from "./components/detail-content.vue";
import DetailBottom from "./components/detail-bottom.vue";
import DetailNewBuy from "./components/detail-new-buy.vue";
import config from "../../../config/index.js";
import SettingPop from "./components/setting-pop.vue";
import CataloguePop from "./components/catalogue-pop.vue";
import VipPop from "./components/vip-pop.vue";
import BeanPop from "./components/bean-pop.vue";
import RecommendPop from "./components/recommend-pop.vue";
import SystemInfoMixin from "../../../common/mixins/system-info-mixin.js";
import {
gotoBookCoverPage
} from "../../../common/services/page-route.js"
import {
watchUserInfoChange,
removeUserInfoChangeWatch,
refreshUserInfo,
postPhone
} from "../../../common/services/userServices.js"
import {
noticeCollectionListChange,
startCountReadTime,
endCountReadTime,
getOpens
} from "../../../common/services/index.js"
import {
saveStorage,
readStorage
} from "../../../common/utils/storageUtil.js";
export default {
mixins: [SystemInfoMixin],
components: {
DetailWarn,
DetailThumb,
DetailContent,
DetailNewBuy,
DetailBottom,
SettingPop,
VipPop,
BeanPop,
RecommendPop,
CataloguePop
},
data() {
return {
bookId: null,
bookData: null,
showSetting: false,
showCatalogue: false,
showVip: false,
showBean: false,
showRecommend: false,
userInfo: null,
showVipOpen: 0,
showBeanOpen: 0,
current: 1
};
},
onLoad(options) {
if (options.bookId) { // 非navigate进入,读取path参数
this.bookId = options.bookId;
} else { // navigate 进入,接受channel传参
const eventChannel = this.getOpenerEventChannel();
eventChannel.on("openBookContentPage", (info) => {
this.bookId = info.bookId;
})
}
},
onReady() {
// 监听用户变动
watchUserInfoChange((info) => {
this.userInfo = info.userInfo;
// 用户已登录需要记录阅读记录
if (info.userInfo && this.bookId) {
addReadRecord(this.bookId)
}
if (this.isVip() && this.bookData) {
this.paySuccess()
}
// // 用户变动,需要刷新数据
// this.$nextTick(() => {
// uni.startPullDownRefresh({})
// })
}, this)
this.$nextTick(() => {
uni.startPullDownRefresh({})
})
// 绑定分享参数
// #ifdef MP-WEIXIN
wx.onCopyUrl(() => {
return {
query: `bookId=${this.bookData.id}`
}
})
// #endif
},
onShow() {
refreshUserInfo();
// 开始记录阅读时长
startCountReadTime();
},
onHide() {
// 停止记录阅读时长
endCountReadTime();
},
onUnload() {
// 停止记录阅读时长,部分情况下页面无法响应onHide事件
endCountReadTime();
// 移除监听
removeUserInfoChangeWatch(this);
// 取消绑定分享参数
// #ifdef MP-WEIXIN
wx.offCopyUrl()
// #endif
},
onPullDownRefresh() {
this.refreshBookData(this.bookId)
},
// 文章分享
onShareAppMessage() {
let result = {
title: this.bookData.title,
imageUrl: this.bookData.cover,
type: config.env == 'Prod' ? 0 : config.env == 'Dev' ? 1 : 2,
path: `/page-subs/sub_A/book-long-content/book-long-content?bookId=${this.bookData.id}`
}
return result;
},
computed: {
showEmpty: function() {
return isEmpty(this.bookData)
},
bgStyle: function() {
let height = 300;
if (this.windowHeight) {
height = this.windowHeight;
}
return {
minHeight: `${height}px`,
position: "relative",
}
}
},
watch: {
bookData: {
handler: function(n) {
if (n) {
uni.setNavigationBarTitle({
title: `阅读:${n.title}`
})
}
}
}
},
methods: {
// 解锁回调
paySuccess() {
this.$set(this.bookData, "isUnlock", 1);
this.$set(this.bookData, "freeNum", this.bookData.articleChapterList.length);
this.$refs.content.reloadChapterinfoData()
},
// 文章数据刷新
refreshBookData(bookId) {
// getOpens((success, data) => {
// this.showBeanOpen = data.openBeans
// this.showVipOpen = data.openVips
// })
getBookDetailData(bookId, (success, data) => {
uni.stopPullDownRefresh();
if (success) {
if (data.isUnlock) {
data.freeNum = data.articleChapterList.length
}
this.bookData = new BookDetail(data);
console.log('bookData=' + JSON.stringify(this.bookData));
}
})
},
// 点击底部按钮
tapBottomItem(e) {
let flag = e.detail.flag;
switch (flag) {
case 'like': // 点赞
break;
case 'collection': // 收藏
let target = !this.bookData.isCollect;
collectionBook(target, this.bookId, (success, data) => {
if (success) {
this.$set(this.bookData, 'isCollect', target);
noticeCollectionListChange(this.bookId, target);
}
})
break;
case 'setting': // 设置
this.showSetting = true;
break;
case 'catalogue': // 目录
this.showCatalogue = true;
break;
default:
break;
}
},
isVip() {
if (this.userInfo != null && this.userInfo.memberExpirationDate > 0) {
return true;
}
return false;
},
tapPayPop() {
if (this.showVipOpen != 1 && this.showBeanOpen == 1) {
this.tapBeanPop()
return
}
this.tapVipPop()
},
// 展示充值VIP弹框
tapVipPop() {
this.showVip = true;
},
// 展示充值书豆弹框
tapBeanPop() {
this.showBean = true;
},
// 关闭设置弹窗
closePop(e) {
this.showSetting = false;
},
// 关闭目录弹窗
closeCataPop(e) {
this.showCatalogue = false;
},
// 关闭会员弹窗
closeVipPop(e) {
this.showVip = false;
if (this.bookData.isUnlock == 0) {
setTimeout(() => {
this.showRecommend = true;
}, 300);
}
},
// 关闭书豆弹窗
closeBeanPop(e) {
this.showBean = false;
// setTimeout(() => {
// this.showRecommend = true;
// }, 300);
},
// 关闭推荐弹窗
closeRecommendPop(e) {
this.showRecommend = false;
},
changeCurrent(current) {
this.current = current
}
}
}
</script>
<style lang="scss">
</style>
\ No newline at end of file
<template>
<uni-popup ref='beanpop' type="bottom" :is-mask-click='false' :safe-area='false' @maskClick='tapMask'>
<view class="setting-box">
<view class="section">
<view class="title">
充值书豆,订阅全本
</view>
<view class="pack-box">
<view class="pack-item" :class="[{active: index==selectedIndex}]" v-for='(item, index) in packData'
:key='index' @click="choosePack(item, index)">
<view class="name row">
{{item.title}}
</view>
<view class="price row">
{{item.price}}
</view>
<view class="cut-down" v-if='item.giveNumber'>
赠送 {{item.giveNumber}} 书豆
</view>
</view>
</view>
</view>
<view class="section">
<button class="c-button_clear c-button-size_lg c-button-width_full apply-button" :disabled="loading"
:loading="loading" @click="tapPay">立即购买</button>
</view>
<view class="safe-placeholder" :style="[safePlacehoderStyle]">
</view>
</view>
</uni-popup>
</template>
<script>
import SystemInfoMixin from "../../../../common/mixins/system-info-mixin.js";
import BookBeanPack from "../../../../common/models/BookBeanPack.js"
import {
getBookBeanPackData,
getOpenId,
getPayInfo,
ENUM_PAY_TYPE
} from "../../../../common/services/index.js";
import PayInfo from "../../../../common/models/PayInfo.js"
import {
watchUserInfoChange,
removeUserInfoChangeWatch,
showLoginView,
refreshUserInfo
} from "../../../../common/services/userServices.js"
import {
toastMessage
} from "../../../../common/utils/toastUtil.js";
import {
px2rpx
} from "../../../../common/utils/util.js";
export default {
mixins: [SystemInfoMixin],
props: {
show: {
type: Boolean,
default: false
}
},
data: function() {
return {
showPop: false,
userInfo: null,
packData: [],
selectedIndex: 0,
loading: false
}
},
computed: {
safePlacehoderStyle: function() {
let height = 0;
if (this.bottomSafeHeight) {
height = height + px2rpx(this.bottomSafeHeight)
}
return {
height: `${height}rpx`
}
},
beanCount: function() {
if (this.userInfo) return this.userInfo.bookLegumes;
return 0;
}
},
watch: {
show: function(n) {
this.showPop = n;
},
showPop: function(n, o) {
if (n == o) return;
if (n) {
this.open();
} else {
this.close();
}
}
},
onReady() {
watchUserInfoChange((info) => {
this.userInfo = info.userInfo;
}, this)
},
onUnload() {
removeUserInfoChangeWatch(this);
},
mounted() {
this.requestPackData();
},
methods: {
open() {
this.$refs.beanpop.open();
},
close() {
this.$emit('close')
this.$refs.beanpop.close();
},
tapMask() {
this.showPop = false;
},
requestPackData() {
getBookBeanPackData((success, data) => {
uni.stopPullDownRefresh()
if (success) {
this.packData = data.map(item => {
return new BookBeanPack(item)
})
}
})
},
choosePack(item, index) {
this.selectedIndex = index;
},
tapPay() {
let isIOS = uni.getSystemInfoSync().platform == "ios" && false
if (isIOS) {
uni.showModal({
title: "提示",
content: "由于相关规范,iOS功能暂不可用"
})
} else {
if (!this.userInfo) {
uni.showModal({
title: "登录",
content: "购买前请前往登录系统",
success: (res) => {
if (res.confirm) {
showLoginView()
}
}
})
return;
}
if (this.loading) return;
let pack = this.packData[this.selectedIndex];
this.loading = true;
let sysLoginFn = (successCB) => {
uni.login({
provider: "weixin",
onlyAuthorize: true,
success: (res) => {
if (res) {
if (typeof successCB == 'function') successCB(res);
} else {
this.loading = false;
}
},
fail: (error) => {
this.loading = false;
}
})
}
let getOpenIdFn = (code, successCB) => {
getOpenId(code, (success, data) => {
if (success) {
if (typeof successCB == 'function') successCB(data);
} else {
this.loading = false;
}
})
}
let getPayInfoFn = (openId, successCB) => {
getPayInfo(pack.id, pack.price, openId, (success, data) => {
if (success) {
if (typeof successCB == 'function') successCB(new PayInfo(data));
} else {
this.loading = false;
}
}, ENUM_PAY_TYPE.BEAN.value)
}
let payOrderFn = (payInfo, successCB) => {
uni.requestPayment({
timeStamp: payInfo.timeStamp,
nonceStr: payInfo.nonceStr,
package: payInfo.packageStr,
signType: payInfo.signType,
paySign: payInfo.paySign,
success: (res) => {
if (typeof successCB == 'function') successCB(res);
},
fail: (error) => {
this.loading = false;
}
})
}
sysLoginFn((code) => {
getOpenIdFn(code.code, (openId) => {
getPayInfoFn(openId, (payInfo) => {
payOrderFn(payInfo, (data) => {
this.loading = false;
toastMessage('购买成功')
refreshUserInfo();
})
})
})
})
}
}
}
}
</script>
<style lang="scss" scoped>
.setting-box {
display: flex;
flex-direction: column;
background: #fff;
padding-top: 20rpx;
border-top-left-radius: 15rpx;
border-top-right-radius: 15rpx;
.section {
padding: 0 30rpx;
display: flex;
flex-direction: column;
background: #fff;
.title {
margin: 10rpx auto;
font-size: 32rpx;
font-weight: 700;
color: #333;
}
.pack-box {
margin-top: 25rpx;
margin-left: 40rpx;
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: wrap;
.active {
border: 6rpx solid #fd5350 !important;
}
.pack-item {
margin-bottom: 25rpx;
margin-right: 40rpx;
width: calc(31% - 40rpx);
height: 200rpx;
display: flex;
flex-direction: column;
justify-content: space-around;
background: #f5f5f5;
border: 6rpx solid #f5f5f5;
border-radius: 10rpx;
position: relative;
.row {
margin: 8rpx 15rpx;
marign-bottom: 0;
}
.row:last-child {
margin-bottom: 8rpx;
}
.name {
font-size: 26rpx;
font-weight: 700;
color: #333;
}
.price {
font-size: 30rpx;
color: #fd5350;
font-weight: 700;
}
.origin {
font-size: 22rpx;
color: #333;
text-decoration: line-through;
}
.cut-down {
position: absolute;
top: 0;
right: 0;
color: #fff;
background: #ff502f;
font-size: 22rpx;
border-radius: 15rpx;
height: 30rpx;
line-height: 30rpx;
padding: 0 10rpx;
transform: translate(0, -50%);
}
}
}
.apply-button {
border-radius: 50rpx;
background: #e8c8ae;
color: #8d5a29;
margin: 30rpx auto;
}
}
}
</style>
\ No newline at end of file
<template>
<uni-popup ref='pop' type="left" :is-mask-click='false' :safe-area='false' @maskClick='tapMask'>
<view @click="tapMask">
<scroll-view scroll-y style="background-color: white;width: 400rpx;max-width: 400rpx;" @click.stop="">
<view class="setting-box">
<block v-for='(item, index) in catalogueList' :key='index' :item='item'>
<view @click.stop="changeCatalogue(item.chapterNum)">
<view
style="display: flex;flex-direction: row;justify-content: space-between;align-items: center;">
<text class="text"
:style="{'width: 350rpx;color': item.chapterNum==currentCatalogue?'#f00':'#000'}">
{{item.chapterNum}}{{item.chapterName}}</text>
<image v-if="(index+1)>detail.freeNum" style="width: 30rpx;height: 30rpx;"
src="https://mints-pkg.oss-cn-beijing.aliyuncs.com/pkg/img/lock.png"></image>
</view>
<view style="background-color: gainsboro;height: 1rpx;width: 400rpx;margin: 20rpx 0;">
</view>
</view>
</block>
</view>
</scroll-view>
</view>
</uni-popup>
</template>
<script>
import SystemInfoMixin from "../../../../common/mixins/system-info-mixin.js";
import {
px2rpx
} from "../../../../common/utils/util.js";
import CatalogueList from "../models/CatalogueList.js";
import {
saveContentFormat,
readContentFormat
} from "../services/index.js"
export default {
mixins: [SystemInfoMixin],
props: {
show: {
type: Boolean,
default: false
},
detail: {
type: Object,
default: 0
},
current: {
type: Number,
default: 0
}
},
data: function() {
return {
showPop: false,
catalogueList: [],
currentContentFormat: {},
currentCatalogue: 1
}
},
computed: {},
watch: {
current: function(n) {
if (n != this.currentCatalogue) {
this.changeCatalogue(n)
}
},
show: function(n) {
this.showPop = n;
},
showPop: function(n, o) {
if (n == o) return;
if (n) {
this.open();
} else {
this.close();
}
}
},
mounted() {
this.initColorList();
this.currentContentFormat = readContentFormat()
for (let i in this.currentContentFormat.catalogueList) {
if (this.currentContentFormat.catalogueList[i].id == this.detail.id) {
// 处理特殊情况,下标错误
let current_e = this.currentContentFormat.catalogueList[i].catalogue
if (!this.detail.isUnlock && current_e > this.detail.freeNum) {
this.currentCatalogue = this.detail.freeNum
return
}
this.currentCatalogue = current_e
}
}
},
methods: {
open() {
this.$refs.pop.open();
},
close() {
this.$emit('close')
this.$refs.pop.close();
},
tapMask() {
this.showPop = false;
},
initColorList() {
this.catalogueList = this.detail.articleChapterList
},
changeCatalogue(e) {
if (e > this.detail.freeNum) {
this.tabVip()
this.close()
return
}
var hasCatalogue = false
for (let i in this.currentContentFormat.catalogueList) {
if (this.currentContentFormat.catalogueList[i].id == this.detail.id) {
this.currentContentFormat.catalogueList[i].catalogue = e
hasCatalogue = true
}
}
if (!hasCatalogue) {
this.currentContentFormat.catalogueList.push({
id: this.detail.id,
catalogue: e
})
}
this.currentCatalogue = e
saveContentFormat(this.currentContentFormat);
this.close()
},
tabVip() {
setTimeout(() => {
this.$emit('tabVip')
}, 1000)
}
}
}
</script>
<style lang="scss" scoped>
.setting-box {
display: flex;
flex-direction: column;
padding: 40rpx;
// background: #fff;
height: 100vh;
.title {
font-size: 34rpx;
font-weight: 700;
}
}
</style>
\ No newline at end of file
<template>
<view class="detail-bottom" :style="[bottomStyle]">
<view class="fixed-bottom" :style="[fixedBottomStyle,{backgroundColor:backgroundColor}]">
<!-- <view class="bottom-item" @click="tapItem('like')">
<uni-icons :type='likeIcon.type' customPrefix="readiconfont" :color='likeIcon.color'
size='20'></uni-icons>
<view class="title" :style="{color: likeIcon.color}">
</view>
</view> -->
<!-- <view class="bottom-item" @click="tapItem('diss')">
<uni-icons :type='dissIcon.type' customPrefix="readiconfont" :color='dissIcon.color'
size='20'></uni-icons>
<view class="title" :style="{color: dissIcon.color}">
</view>
</view> -->
<view class="bottom-item" @click="tapItem('catalogue')">
<uni-icons type='icon-uncollection' customPrefix="readiconfont" color='#333' size='20'></uni-icons>
<view class="title" :style="{color: '#333'}">
目录
</view>
</view>
<!-- <view class="bottom-item" @click="tapItem('collection')">
<uni-icons :type='collectionIcon.type' customPrefix="readiconfont" :color='collectionIcon.color'
size='20'></uni-icons>
<view class="title" :style="{color: collectionIcon.color}">
{{collectionIcon.title}}
</view>
</view> -->
<view class="bottom-item" @click="tapItem('setting')">
<uni-icons type='icon-setting' customPrefix="readiconfont" color='#333' size='20'></uni-icons>
<view class="title" :style="{color: '#333'}">
设置
</view>
</view>
<view class="bottom-item">
<uni-icons type='icon-share' customPrefix="readiconfont" color='#333' size='20'></uni-icons>
<view class="title" :style="{color: '#333'}">
分享
</view>
<button class="c-button_clear cover-button" open-type="share"></button>
</view>
</view>
<view class="safe-placeholder" :style="[safePlaceholderStyle]"></view>
</view>
</template>
<script>
import {
watchContentFormatChange,
removeContentFormatChangeWatch
} from "../services/index.js"
import SystemInfoMixin from "../../../../common/mixins/system-info-mixin.js"
import {
px2rpx
} from "../../../../common/utils/util.js";
import {
showLoginView
} from "../../../../common/services/userServices.js"
export default {
mixins: [SystemInfoMixin],
props: {
detail: {
type: Object,
default: function() {
return {}
}
},
userInfo: {
type: Object,
default: function() {
return null
}
}
},
data: function() {
return {
height: `100`,
backgroundColor: `#fff`
}
},
mounted() {
// 监听样式变动
watchContentFormatChange((data) => {
let result = data.getFormatValue();
if (this.backgroundColor != result.backgroundColor) {
this.backgroundColor = result.backgroundColor
}
}, this)
},
destroyed() {
removeContentFormatChangeWatch(this);
},
computed: {
fixedBottomStyle: function() {
let height = 0;
if (this.bottomSafeHeight) {
height = height + px2rpx(this.bottomSafeHeight)
}
return {
bottom: `${height}rpx`
}
},
safePlaceholderStyle: function() {
let height = 0;
if (this.bottomSafeHeight) {
height = height + px2rpx(this.bottomSafeHeight)
}
return {
height: `${height}rpx`
}
},
bottomStyle: function() {
let height = 100;
if (this.bottomSafeHeight) {
height = height + px2rpx(this.bottomSafeHeight)
}
return {
height: `${height}rpx`
}
},
likeIcon: function() {
return {
type: this.detail.isLike ? 'icon-like' : 'icon-unlike',
color: this.detail.isLike ? '#FECF02' : "#333"
}
},
dissIcon: function() {
return {
type: this.detail.isDiss ? 'icon-diss' : 'icon-undiss',
color: this.detail.isDiss ? '#FECF02' : "#333"
}
},
collectionIcon: function() {
return {
type: this.detail.isCollect ? 'icon-collection' : 'icon-uncollection',
color: this.detail.isCollect ? '#FECF02' : "#333",
title: this.detail.isCollect ? "已收藏" : "收藏"
}
}
},
methods: {
tapItem(flag) {
if (flag == 'collection' && !this.userInfo) {
showLoginView();
return;
}
this.$emit("tapBottomItem", {
detail: {
flag,
item: this.detail
}
})
}
}
}
</script>
<style lang="scss" scoped>
.detail-bottom {
position: absolute;
height: 100rpx;
bottom: 0;
z-index: 99;
.fixed-bottom {
position: fixed;
background: transparent;
bottom: 0;
left: 0;
right: 0;
height: 100rpx;
display: flex;
flex-direction: row;
align-items: center;
.bottom-item {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
// width: 33.3333333333%;
flex: 1;
.title {
font-size: 24rpx;
margin-top: 10rpx;
}
.cover-button {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: transparent;
z-index: 2;
}
}
}
.safe-placeholder {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background: #fff;
}
}
</style>
\ No newline at end of file
<template>
<view class="detail-thumb" @click="tapThumb">
<view class="content">
<view class="cover-box item">
<image class="cover" :src="detail.avatar" mode="aspectFill"></image>
</view>
<view class="info-box item">
<view class="row">
<view class="title">
{{detail.title}}
</view>
</view>
<view class="row">
<view class="desc">
{{detail.summary}}
</view>
</view>
<view class="row">
<view class="author-box">
<uni-icons type='icon-author' custom-prefix="readiconfont" size='20'
color='#378eff'></uni-icons>
<view class="name">
{{detail.author}}
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
detail: {
type: Object,
default: function() {
return {}
}
}
},
data: function() {
return {
imageError: true
}
},
methods: {
tapThumb() {
this.$emit('tapThumb', {
detail: {
data: this.detail
}
})
},
loadImage() {
this.imageError = false
},
errorImage() {
this.imageError = true
}
}
}
</script>
<style lang="scss" scoped>
page {
background: #fff;
}
.detail-thumb {
padding: 15rpx 30rpx;
display: flex;
flex-direction: column;
.content {
display: flex;
flex-direction: row;
align-items: center;
border-radius: 18rpx;
background: #f5f5f5;
padding: 20rpx;
.row {
margin-bottom: 20rpx;
}
.row:last-child {
margin-bottom: 0;
}
.item {
margin-right: 20rpx;
}
.item:last-child {
margin-right: 0;
}
.cover-box {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.cover {
width: 140rpx;
height: 180rpx;
border-radius: 15rpx;
}
}
.info-box {
flex: 1;
display: flex;
flex-direction: column;
.title {
font-size: 32rpx;
font-weight: 700;
color: #333;
}
.desc {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-size: 24rpx;
color: #999
}
.author-box {
display: flex;
flex-direction: row;
align-items: center;
height: 50rpx;
line-height: 50rpx;
.name {
font-size: 26rpx;
color: #378eff;
margin-left: 15rpx;
}
}
}
}
}
</style>
\ No newline at end of file
<template>
<view v-if="false" class="detail-warn">
<view class="content">
<uni-icons type='chatboxes' size="20" color="#aa8062"></uni-icons>
<view class="value">
"本故事纯属虚构,仅供娱乐,无不良引导"
</view>
</view>
</view>
</template>
<script>
</script>
<style lang="scss" scoped>
.detail-warn {
padding: 15rpx 30rpx;
display: flex;
flex-direction: column;
.content {
height: 100rpx;
line-height: 100rpx;
display: flex;
flex-direction: row;
align-items: center;
border-radius: 18rpx;
background: #f4e9eb;
color: #aa8062;
padding: 0 30rpx;
.value {
font-size: 28rpx;
margin-left: 15rpx;
}
}
}
</style>
\ No newline at end of file
This diff is collapsed.
import Book from "../../../../common/models/Book";
export default class BookDetail extends Book {
constructor(param) {
super(param);
const {
contentMd
} = param || {}
this.contentMd = contentMd;
let result = contentMd ? contentMd.replace(/<[^>]+>/g, "") : "";
result = result.split("\n");
this.content = result.filter(item => {
return item.split(/[\t\r\f\n\s]*/g).join("");
});
}
}
\ No newline at end of file
export default class CatalogueList {
constructor(param) {
const {
id,
catalogue,
} = param || {}
this.id = id;
this.catalogue = catalogue;
}
getFormatValue() {
return {
id: this.id,
catalogue: this.catalogue
}
}
}
\ No newline at end of file
export default class ContentFormat {
constructor(param) {
const {
fontSize,
backgroundColor,
catalogueList,
} = param || {}
this.fontSize = fontSize;
this.catalogueList = catalogueList;
this.backgroundColor = backgroundColor;
}
getFormatValue() {
return {
fontSize: `${this.fontSize}px`,
backgroundColor: this.backgroundColor,
catalogueList: this.catalogueList
}
}
}
\ No newline at end of file
This diff is collapsed.
<template>
<view>
<scroll-view scroll-y style="height: 100%;background: #FFF7F7;">
<search-header-bar id='headerBar' :keyword='keyword' @clear='clearSearch'
@start='startSearch'></search-header-bar>
<view :style='[placeholderViewStyle]'>
......@@ -10,8 +10,8 @@
<search-result-view ref='searchList' :height='listHeight' :keyword='keyword' :searchType='searchType'
:result='result' @change='changeResult'></search-result-view>
</view>
<c-login></c-login>
</view>
<view style="height: 20rpx;"></view>
</scroll-view>
</template>
<script>
......@@ -109,7 +109,5 @@
</script>
<style lang="scss" scoped>
.test {
display: none;
}
</style>
\ No newline at end of file
......@@ -90,7 +90,6 @@
display: flex;
flex-direction: row;
align-items: center;
background: #fff;
font-size: 28rpx;
.item {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment