Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
U
uniapp_vedio
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
android
uniapp_vedio
Commits
528d4299
Commit
528d4299
authored
Aug 06, 2024
by
jyx
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
代码优化
parent
6d82d603
Changes
26
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
3538 additions
and
158 deletions
+3538
-158
Book.js
vedio/common/models/Book.js
+2
-0
page-route.js
vedio/common/services/page-route.js
+93
-71
bookshelf-list.vue
vedio/components/bookshelf/components/bookshelf-list.vue
+1
-1
warehouse-list.vue
vedio/components/warehouse/components/warehouse-list.vue
+80
-80
warehouse.vue
vedio/components/warehouse/warehouse.vue
+1
-1
recommend-pop.vue
...page-subs/sub_A/book-content/components/recommend-pop.vue
+1
-1
book-long-content.vue
...o/page-subs/sub_A/book-long-content/book-long-content.vue
+357
-0
bean-pop.vue
...page-subs/sub_A/book-long-content/components/bean-pop.vue
+325
-0
catalogue-pop.vue
...subs/sub_A/book-long-content/components/catalogue-pop.vue
+138
-0
detail-bottom.vue
...subs/sub_A/book-long-content/components/detail-bottom.vue
+212
-0
detail-buy.vue
...ge-subs/sub_A/book-long-content/components/detail-buy.vue
+495
-0
detail-content-flip.vue
...ub_A/book-long-content/components/detail-content-flip.vue
+165
-0
detail-content.vue
...ubs/sub_A/book-long-content/components/detail-content.vue
+173
-0
detail-new-buy.vue
...ubs/sub_A/book-long-content/components/detail-new-buy.vue
+282
-0
detail-thumb.vue
...-subs/sub_A/book-long-content/components/detail-thumb.vue
+152
-0
detail-warn.vue
...e-subs/sub_A/book-long-content/components/detail-warn.vue
+38
-0
recommend-pop.vue
...subs/sub_A/book-long-content/components/recommend-pop.vue
+347
-0
setting-pop.vue
...e-subs/sub_A/book-long-content/components/setting-pop.vue
+164
-0
vip-pop.vue
.../page-subs/sub_A/book-long-content/components/vip-pop.vue
+320
-0
BookDetail.js
vedio/page-subs/sub_A/book-long-content/models/BookDetail.js
+16
-0
CatalogueList.js
...page-subs/sub_A/book-long-content/models/CatalogueList.js
+16
-0
ContentFormat.js
...page-subs/sub_A/book-long-content/models/ContentFormat.js
+19
-0
index.js
vedio/page-subs/sub_A/book-long-content/services/index.js
+130
-0
recommond-item.vue
...page-subs/sub_A/book-search/components/recommond-item.vue
+1
-1
search-result.vue
.../page-subs/sub_A/book-search/components/search-result.vue
+3
-3
pages.json
vedio/pages.json
+7
-0
No files found.
vedio/common/models/Book.js
View file @
528d4299
...
...
@@ -25,6 +25,7 @@ export default class Book {
createTime
,
tagList
,
isUnlock
,
shortis
,
free
,
charge
,
bookLegumes
,
...
...
@@ -56,6 +57,7 @@ export default class Book {
this
.
categoryId
=
categoryId
;
this
.
createTime
=
createTime
;
this
.
isUnlock
=
isUnlock
;
this
.
shortis
=
shortis
;
this
.
charge
=
charge
;
this
.
free
=
free
;
this
.
bookLegumes
=
bookLegumes
;
...
...
vedio/common/services/page-route.js
View file @
528d4299
const
{
ENUM_SEARCH_TYPE
,
ENUM_MESSAGE_PAGE_TYPE
}
=
require
(
"../../static/enums/enum_value"
);
// 搜索页面
function
gotoBookSearchPage
(
searchType
=
ENUM_SEARCH_TYPE
.
WAREHOUSE
,
keyword
)
{
uni
.
navigateTo
({
url
:
`/page-subs/sub_A/book-search/book-search`
,
success
:
(
res
)
=>
{
res
.
eventChannel
.
emit
(
"openBookSearchPage"
,
{
keyword
,
searchType
})
}
})
}
// 文章详情
function
gotoBookContentPage
(
bookId
)
{
uni
.
navigateTo
({
url
:
`/page-subs/sub_A/book-content/book-content`
,
success
:
(
res
)
=>
{
res
.
eventChannel
.
emit
(
"openBookContentPage"
,
{
bookId
})
}
})
}
// 文章封面
function
gotoBookCoverPage
(
bookId
)
{
return
;
uni
.
navigateTo
({
url
:
`/page-subs/sub_A/book-cover/book-cover`
,
success
:
(
res
)
=>
{
res
.
eventChannel
.
emit
(
"openBookCoverPage"
,
{
bookId
})
}
})
}
// vip申请
function
gotoVIPApplyPage
()
{
uni
.
navigateTo
({
url
:
`/pagesA//vipPay/vipPay`
,
})
}
// 用户编辑
function
gotoUserEditPage
(
userInfo
)
{
uni
.
navigateTo
({
url
:
`/page-subs/sub_B/user-edit/user-edit`
,
success
:
(
res
)
=>
{
res
.
eventChannel
.
emit
(
"openUserEditPage"
,
{
userInfo
})
}
})
}
module
.
exports
=
{
/** sub_A */
gotoBookSearchPage
,
gotoBookContentPage
,
gotoBookCoverPage
,
/** sub_B */
gotoVIPApplyPage
,
gotoUserEditPage
,
const
{
ENUM_SEARCH_TYPE
,
ENUM_MESSAGE_PAGE_TYPE
}
=
require
(
"../../static/enums/enum_value"
);
// 搜索页面
function
gotoBookSearchPage
(
searchType
=
ENUM_SEARCH_TYPE
.
WAREHOUSE
,
keyword
)
{
uni
.
navigateTo
({
url
:
`/page-subs/sub_A/book-search/book-search`
,
success
:
(
res
)
=>
{
res
.
eventChannel
.
emit
(
"openBookSearchPage"
,
{
keyword
,
searchType
})
}
})
}
// 文章详情
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?bookId=`
+
bookId
,
success
:
(
res
)
=>
{
res
.
eventChannel
.
emit
(
"openBookContentPage"
,
{
bookId
})
}
})
}
// 长篇文章详情
function
gotoLongBookContentPage
(
bookId
)
{
uni
.
navigateTo
({
url
:
`/page-subs/sub_A/book-long-content/book-long-content?bookId=`
+
bookId
,
success
:
(
res
)
=>
{
res
.
eventChannel
.
emit
(
"openBookContentPage"
,
{
bookId
})
}
})
}
// 文章封面
function
gotoBookCoverPage
(
bookId
)
{
return
;
uni
.
navigateTo
({
url
:
`/page-subs/sub_A/book-cover/book-cover`
,
success
:
(
res
)
=>
{
res
.
eventChannel
.
emit
(
"openBookCoverPage"
,
{
bookId
})
}
})
}
// vip申请
function
gotoVIPApplyPage
()
{
uni
.
navigateTo
({
url
:
`/pagesA//vipPay/vipPay`
,
})
}
// 用户编辑
function
gotoUserEditPage
(
userInfo
)
{
uni
.
navigateTo
({
url
:
`/page-subs/sub_B/user-edit/user-edit`
,
success
:
(
res
)
=>
{
res
.
eventChannel
.
emit
(
"openUserEditPage"
,
{
userInfo
})
}
})
}
module
.
exports
=
{
/** sub_A */
gotoBookSearchPage
,
gotoBookContentPage
,
gotoBookCoverPage
,
/** sub_B */
gotoVIPApplyPage
,
gotoUserEditPage
,
}
\ No newline at end of file
vedio/components/bookshelf/components/bookshelf-list.vue
View file @
528d4299
...
...
@@ -65,7 +65,7 @@
})
},
tapItem
(
e
,
index
)
{
gotoBookContentPage
(
e
.
detail
.
data
.
id
)
gotoBookContentPage
(
e
.
detail
.
data
.
id
,
e
.
detail
.
data
.
shortis
)
},
tapClose
(
e
,
index
)
{
let
item
=
e
.
detail
.
data
;
...
...
vedio/components/warehouse/components/warehouse-list.vue
View file @
528d4299
<
template
>
<view>
<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>
</c-list>
</view>
</
template
>
<
script
>
import
{
gotoBookContentPage
}
from
'../../../common/services/page-route'
;
import
{
isEmpty
}
from
'../../../common/utils/util'
import
WarehouseBookItem
from
'../models/WarehouseBookItem.js'
;
export
default
{
components
:
{},
props
:
{
height
:
{
type
:
Number
,
default
:
0
},
category
:
{
type
:
Object
,
default
:
function
()
{
return
{}
}
},
},
data
:
function
()
{
return
{
dataList
:
[],
}
},
computed
:
{
requestParam
:
function
()
{
return
{
categoryId
:
this
.
category
.
value
}
}
},
watch
:
{},
methods
:
{
initRefresh
()
{
if
(
isEmpty
(
this
.
dataList
))
{
this
.
refreshList
();
}
},
refreshList
()
{
this
.
$nextTick
(()
=>
{
let
ref
=
this
.
$refs
.
list
;
if
(
ref
)
{
ref
.
onPullRefreshing
();
}
})
},
changeData
(
e
)
{
this
.
dataList
=
e
.
detail
.
data
.
map
(
item
=>
{
return
new
WarehouseBookItem
(
item
)
})
},
tapItem
(
e
,
index
)
{
gotoBookContentPage
(
e
.
detail
.
data
.
id
)
},
tapClose
(
e
,
index
)
{
// TODO 仓库点击关闭按钮,弹窗选择关闭原因
uni
.
showModal
({
title
:
"不喜欢"
,
content
:
`是否确认减少推荐此类书籍?`
})
}
}
}
</
script
>
<
style
>
<
template
>
<view>
<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>
</c-list>
</view>
</
template
>
<
script
>
import
{
gotoBookContentPage
}
from
'../../../common/services/page-route'
;
import
{
isEmpty
}
from
'../../../common/utils/util'
import
WarehouseBookItem
from
'../models/WarehouseBookItem.js'
;
export
default
{
components
:
{},
props
:
{
height
:
{
type
:
Number
,
default
:
0
},
category
:
{
type
:
Object
,
default
:
function
()
{
return
{}
}
},
},
data
:
function
()
{
return
{
dataList
:
[],
}
},
computed
:
{
requestParam
:
function
()
{
return
{
categoryId
:
this
.
category
.
value
}
}
},
watch
:
{},
methods
:
{
initRefresh
()
{
if
(
isEmpty
(
this
.
dataList
))
{
this
.
refreshList
();
}
},
refreshList
()
{
this
.
$nextTick
(()
=>
{
let
ref
=
this
.
$refs
.
list
;
if
(
ref
)
{
ref
.
onPullRefreshing
();
}
})
},
changeData
(
e
)
{
this
.
dataList
=
e
.
detail
.
data
.
map
(
item
=>
{
return
new
WarehouseBookItem
(
item
)
})
},
tapItem
(
e
,
index
)
{
gotoBookContentPage
(
e
.
detail
.
data
.
id
,
e
.
detail
.
data
.
shortis
)
},
tapClose
(
e
,
index
)
{
// TODO 仓库点击关闭按钮,弹窗选择关闭原因
uni
.
showModal
({
title
:
"不喜欢"
,
content
:
`是否确认减少推荐此类书籍?`
})
}
}
}
</
script
>
<
style
>
</
style
>
\ No newline at end of file
vedio/components/warehouse/warehouse.vue
View file @
528d4299
...
...
@@ -120,7 +120,7 @@
setTimeout
(()
=>
{
// 匹配用户直接跳转小说
if
(
data
.
articleMsg
!=
null
)
{
gotoBookContentPage
(
data
.
articleMsg
.
id
);
gotoBookContentPage
(
data
.
articleMsg
.
id
,
data
.
articleMsg
.
shortis
);
}
},
800
);
}
...
...
vedio/page-subs/sub_A/book-content/components/recommend-pop.vue
View file @
528d4299
...
...
@@ -128,7 +128,7 @@
uni
.
navigateBack
({
delta
:
2
});
gotoBookContentPage
(
item
.
id
);
gotoBookContentPage
(
item
.
id
,
item
.
shortis
);
}
}
}
...
...
vedio/page-subs/sub_A/book-long-content/book-long-content.vue
0 → 100644
View file @
528d4299
<
template
>
<view
:style=
"[bgStyle]"
>
<c-empty
v-if=
'showEmpty'
></c-empty>
<template
v-else
>
<detail-content-flip
:detail=
'bookData'
:userInfo=
'userInfo'
@
tabVip2=
"tapVipPop"
></detail-content-flip>
<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'
@
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>
</
template
>
<!-- <c-login :isShareLink="true"></c-login> -->
<popup
:show=
"showMoibleLogin"
@
close=
"showMoibleLogin=false"
>
<view>
<button
open-type=
"getPhoneNumber"
@
getphonenumber=
"MygetPhonenumber"
>
<view>
请先绑定手机号
</view>
<view
style=
"color:green;"
>
去绑定
</view>
</button>
</view>
</popup>
</view>
</template>
<
script
>
import
{
isEmpty
}
from
"../../../common/utils/util.js"
;
import
BookDetail
from
"./models/BookDetail.js"
;
import
{
getBookDetailData
,
watchContentFormatChange
,
removeContentFormatChangeWatch
,
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
DetailContentFlip
from
"./components/detail-content-flip.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
,
getChapterinfoData
}
from
"../../../common/services/index.js"
import
{
saveStorage
,
readStorage
}
from
"../../../common/utils/storageUtil.js"
;
export
default
{
mixins
:
[
SystemInfoMixin
],
components
:
{
DetailWarn
,
DetailThumb
,
DetailContent
,
DetailContentFlip
,
DetailNewBuy
,
DetailBottom
,
SettingPop
,
VipPop
,
BeanPop
,
RecommendPop
,
CataloguePop
},
data
()
{
return
{
bookId
:
null
,
bookData
:
null
,
backgroundColor
:
"#fff"
,
showSetting
:
false
,
showCatalogue
:
false
,
showVip
:
false
,
showBean
:
false
,
showRecommend
:
false
,
userInfo
:
null
,
showVipOpen
:
0
,
showBeanOpen
:
0
,
showMoibleLogin
:
false
,
mobileLoginLock
:
false
,
};
},
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
;
})
}
this
.
mobileLoginLock
=
readStorage
(
"KEY_NEED_PHONE"
)
},
onReady
()
{
// 监听样式变动
watchContentFormatChange
((
data
)
=>
{
let
result
=
data
.
getFormatValue
();
if
(
this
.
backgroundColor
!=
result
.
backgroundColor
)
{
this
.
backgroundColor
=
result
.
backgroundColor
}
},
this
)
// 监听用户变动
watchUserInfoChange
((
info
)
=>
{
this
.
userInfo
=
info
.
userInfo
;
// 用户已登录需要记录阅读记录
if
(
info
.
userInfo
&&
this
.
bookId
)
{
addReadRecord
(
this
.
bookId
)
}
// // 用户变动,需要刷新数据
// 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
();
// 移除监听
removeContentFormatChangeWatch
(
this
);
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"
,
background
:
this
.
backgroundColor
}
}
},
watch
:
{
bookData
:
{
handler
:
function
(
n
)
{
if
(
n
)
{
uni
.
setNavigationBarTitle
({
title
:
`阅读:
${
n
.
title
}
`
})
}
}
}
},
methods
:
{
async
MygetPhonenumber
(
e
)
{
console
.
log
(
e
.
detail
.
code
)
// 动态令牌
console
.
log
(
e
.
detail
.
errMsg
)
// 回调信息(成功失败都会返回)
console
.
log
(
e
.
detail
.
errno
)
// 错误码(失败时返回)
this
.
showMoibleLogin
=
false
if
(
e
.
detail
.
code
==
undefined
||
e
.
detail
.
code
==
''
)
{
uni
.
showModal
({
title
:
"提示"
,
content
:
e
.
detail
.
errMsg
})
return
}
var
params
=
{
userId
:
this
.
userInfo
.
userid
,
code
:
e
.
detail
.
code
,
}
postPhone
(
params
,
(
success
,
result
)
=>
{
if
(
success
)
{
saveStorage
(
"KEY_NEED_PHONE"
,
false
);
this
.
mobileLoginLock
=
false
this
.
tapPayPop
()
}
else
{
uni
.
showModal
({
title
:
"提示"
,
content
:
"网络错误!"
})
}
})
},
// 解锁回调
unlockBook
()
{
this
.
$set
(
this
.
bookData
,
"isUnlock"
,
true
);
},
// 文章数据刷新
refreshBookData
(
bookId
)
{
// getOpens((success, data) => {
// this.showBeanOpen = data.openBeans
// this.showVipOpen = data.openVips
// })
getBookDetailData
(
bookId
,
(
success
,
data
)
=>
{
setTimeout
(()
=>
{
uni
.
stopPullDownRefresh
();
if
(
success
)
{
this
.
bookData
=
new
BookDetail
(
data
);
console
.
log
(
'bookData='
+
JSON
.
stringify
(
this
.
bookData
));
}
},
1000
)
})
},
// 点击底部按钮
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
.
memberFlag
)
{
let
cDate
=
new
Date
();
cDate
=
cDate
.
getTime
();
return
this
.
userInfo
.
memberExpirationDate
>=
cDate
;
}
return
false
;
},
tapPayPop
()
{
if
(
this
.
showVipOpen
!=
1
&&
this
.
showBeanOpen
==
1
)
{
this
.
tapBeanPop
()
return
}
this
.
tapVipPop
()
},
// 展示充值VIP弹框
tapVipPop
()
{
if
(
this
.
mobileLoginLock
)
{
this
.
showMoibleLogin
=
true
return
}
this
.
showVip
=
true
;
},
// 展示充值书豆弹框
tapBeanPop
()
{
if
(
this
.
mobileLoginLock
)
{
this
.
showMoibleLogin
=
true
return
}
this
.
showBean
=
true
;
},
// 关闭设置弹窗
closePop
(
e
)
{
this
.
showSetting
=
false
;
},
// 关闭目录弹窗
closeCataPop
(
e
)
{
this
.
showCatalogue
=
false
;
},
// 关闭会员弹窗
closeVipPop
(
e
)
{
this
.
showVip
=
false
;
// setTimeout(() => {
// this.showRecommend = true;
// }, 300);
},
// 关闭书豆弹窗
closeBeanPop
(
e
)
{
this
.
showBean
=
false
;
// setTimeout(() => {
// this.showRecommend = true;
// }, 300);
},
// 关闭推荐弹窗
closeRecommendPop
(
e
)
{
this
.
showRecommend
=
false
;
},
}
}
</
script
>
<
style
lang=
"scss"
>
</
style
>
\ No newline at end of file
vedio/page-subs/sub_A/book-long-content/components/bean-pop.vue
0 → 100644
View file @
528d4299
<
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
vedio/page-subs/sub_A/book-long-content/components/catalogue-pop.vue
0 → 100644
View file @
528d4299
<
template
>
<uni-popup
ref=
'pop'
type=
"left"
:is-mask-click=
'false'
:safe-area=
'false'
@
maskClick=
'tapMask'
>
<scroll-view
scroll-y
style=
"background-color: white;"
>
<view
class=
"setting-box"
>
<block
v-for=
'(item, index) in catalogueList'
:key=
'index'
:item=
'item'
>
<view
@
click=
"changeCatalogue(item.chapterNum)"
>
<view
style=
"width: 400rpx;max-width: 400rpx;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>
</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
}
},
data
:
function
()
{
return
{
showPop
:
false
,
catalogueList
:
[],
currentContentFormat
:
{},
currentCatalogue
:
1
}
},
computed
:
{},
watch
:
{
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
)
{
this
.
currentCatalogue
=
this
.
currentContentFormat
.
catalogueList
[
i
].
catalogue
}
}
},
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
})
}
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
vedio/page-subs/sub_A/book-long-content/components/detail-bottom.vue
0 → 100644
View file @
528d4299
<
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
;
.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
vedio/page-subs/sub_A/book-long-content/components/detail-buy.vue
0 → 100644
View file @
528d4299
This diff is collapsed.
Click to expand it.
vedio/page-subs/sub_A/book-long-content/components/detail-content-flip.vue
0 → 100644
View file @
528d4299
<
template
>
<view
class=
"detail-content"
>
<template>
<yingbing-ReadPage
ref=
"page"
:fontSize=
"fontSize"
:bgColor=
"backgroundColor"
style=
"height: 100vh;"
@
loadmore=
"onLoadmore"
>
</yingbing-ReadPage>
</
template
>
</view>
</template>
<
script
>
import
{
watchContentFormatChange
,
removeContentFormatChangeWatch
,
getChapterinfoData
}
from
"../services/index.js"
import
cataloguePopVue
from
"./catalogue-pop.vue"
;
export
default
{
props
:
{
userInfo
:
{
type
:
Object
,
default
:
function
()
{
return
null
}
},
detail
:
{
type
:
Object
,
default
:
function
()
{
return
{}
}
}
},
data
:
function
()
{
return
{
fontSize
:
'18'
,
backgroundColor
:
"#fff"
,
catalogue
:
1
,
}
},
mounted
()
{
// 监听样式变动
watchContentFormatChange
((
data
)
=>
{
let
result
=
data
.
getFormatValue
();
if
(
this
.
fontSize
!=
result
.
fontSize
)
{
this
.
fontSize
=
result
.
fontSize
.
substring
(
0
,
2
)
}
if
(
this
.
backgroundColor
!=
result
.
backgroundColor
)
{
this
.
backgroundColor
=
result
.
backgroundColor
}
let
resultCatalogue
=
1
for
(
let
i
in
result
.
catalogueList
)
{
if
(
result
.
catalogueList
[
i
].
id
==
this
.
detail
.
id
)
{
resultCatalogue
=
result
.
catalogueList
[
i
].
catalogue
}
}
if
(
this
.
catalogue
!=
resultCatalogue
)
{
this
.
catalogue
=
resultCatalogue
this
.
refreshChapterinfoData
(
this
.
catalogue
)
}
},
this
)
},
destroyed
()
{
removeContentFormatChangeWatch
(
this
);
},
onReady
()
{
this
.
refreshChapterinfoData
(
this
.
catalogue
)
},
methods
:
{
onLoadmore
(
chapter
,
callback
)
{
if
(
chapter
>=
this
.
detail
.
freeNum
)
{
this
.
tabVip
()
return
}
getChapterinfoData
(
this
.
detail
.
id
,
chapter
,
(
success
,
data
)
=>
{
if
(
success
)
{
this
.
catalogue
=
chapter
let
mycontent
=
data
.
content
.
replace
(
/<
(\/)?
p>/g
,
''
).
replace
(
/<
(\/)?
sub>/g
,
''
).
replace
(
/<
(\/)?
pre>/g
,
''
)
.
replace
(
/<
(\/)?
code>/g
,
''
)
let
content
=
{
chapter
:
chapter
,
content
:
mycontent
,
title
:
'第'
+
chapter
+
'章'
,
isStart
:
chapter
==
1
,
isEnd
:
chapter
==
this
.
detail
.
articleChapterList
.
length
}
callback
(
'success'
,
content
)
}
})
},
// 文章数据刷新
refreshChapterinfoData
(
chapterId
,
callback
)
{
this
.
catalogue
=
chapterId
let
id
=
this
.
detail
.
articleChapterList
[
chapterId
].
id
getChapterinfoData
(
this
.
detail
.
id
,
id
,
(
success
,
data
)
=>
{
if
(
success
)
{
this
.
changeChapterinfo
(
chapterId
,
data
.
content
)
}
})
},
changeChapterinfo
(
chapterId
,
content
)
{
this
.
catalogue
=
chapterId
let
mycontent
=
content
.
replace
(
/<
(\/)?
p>/g
,
''
).
replace
(
/<
(\/)?
sub>/g
,
''
).
replace
(
/<
(\/)?
pre>/g
,
''
)
.
replace
(
/<
(\/)?
code>/g
,
''
)
let
contents
=
[{
chapter
:
chapterId
,
//章节序号
content
:
mycontent
,
title
:
'第'
+
chapterId
+
'章'
,
//章节标题
isStart
:
chapterId
==
1
,
//是否是第一章节
isEnd
:
false
,
//是否是最后一个章节
}]
const
{
page
}
=
this
.
$refs
;
page
.
change
({
contents
:
contents
,
currentChapter
:
chapterId
,
//从第二章节开始阅读 和章节chapter对应
start
:
0
//从章节的第100个字开始阅读
})
},
tabVip
()
{
setTimeout
(()
=>
{
this
.
$emit
(
'tabVip2'
)
},
1000
)
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.detail-content
{
display
:
flex
;
flex-direction
:
column
;
.content-paragraph
{
text-indent
:
1em
;
word-wrap
:
break-word
;
word-break
:
break-all
;
white-space
:
normal
;
line-height
:
1
.5em
;
margin-bottom
:
1em
;
color
:
#333
;
}
.content-paragraph
:last-child
{
margin-bottom
:
0
;
}
.limit-button-box
{
text-indent
:
0
;
height
:
120rpx
;
line-height
:
120rpx
;
text-align
:
center
;
color
:
goldenrod
;
font-size
:
28rpx
;
}
}
</
style
>
\ No newline at end of file
vedio/page-subs/sub_A/book-long-content/components/detail-content.vue
0 → 100644
View file @
528d4299
<
template
>
<view
class=
"detail-content"
>
<template
v-if=
'showVIPContent'
>
<view
class=
"content-paragraph"
:style=
"[contentStyle]"
v-for=
'(item, index) in contentSources'
:key=
'index'
>
{{
item
}}
</view>
</
template
>
<
template
v-else
>
<view
class=
"content-paragraph"
:style=
"[contentStyle]"
v-for=
'(item, index) in preContentSources'
:key=
"index"
>
{{
item
}}
</view>
<view
class=
"limit-button-box"
@
click=
"tapVip"
>
{{
limitButtonTitle
}}
</view>
</
template
>
</view>
</template>
<
script
>
import
{
watchContentFormatChange
,
removeContentFormatChangeWatch
}
from
"../services/index.js"
import
{
showLoginView
}
from
"../../../../common/services/userServices.js"
import
{
gotoVIPApplyPage
}
from
"../../../../common/services/page-route.js"
import
User
from
"../../../../common/models/User.js"
;
export
default
{
props
:
{
userInfo
:
{
type
:
Object
,
default
:
function
()
{
return
null
}
},
detail
:
{
type
:
Object
,
default
:
function
()
{
return
{}
}
}
},
data
:
function
()
{
return
{
user
:
null
,
fontSize
:
`18px`
,
PRECENT_VALUE
:
40
}
},
mounted
()
{
watchContentFormatChange
((
data
)
=>
{
let
result
=
data
.
getFormatValue
();
if
(
this
.
fontSize
!=
result
.
fontSize
)
{
this
.
fontSize
=
result
.
fontSize
}
},
this
)
},
destroyed
()
{
removeContentFormatChangeWatch
(
this
);
},
watch
:
{
userInfo
:
{
handler
:
function
(
n
)
{
if
(
n
)
{
this
.
user
=
new
User
(
n
)
}
else
{
this
.
user
=
null
}
},
deep
:
true
,
immediate
:
true
}
},
computed
:
{
contentSources
:
function
()
{
return
this
.
detail
&&
this
.
detail
.
content
?
this
.
detail
.
content
:
[];
},
preContentSources
:
function
()
{
let
result
=
this
.
detail
&&
this
.
detail
.
content
?
[...
this
.
detail
.
content
]
:
[];
let
length
=
result
.
length
;
if
(
length
>=
2
)
{
if
(
this
.
detail
.
lockRate
!=
null
&&
this
.
detail
.
lockRate
>
0
){
this
.
PRECENT_VALUE
=
this
.
detail
.
lockRate
;
}
console
.
log
(
'this.PRECENT_VALUE='
+
this
.
PRECENT_VALUE
);
let
precent
=
this
.
PRECENT_VALUE
/
100
;
let
preLength
=
Math
.
floor
(
length
*
precent
);
return
result
.
splice
(
0
,
preLength
);
}
else
{
return
result
;
}
},
limitButtonTitle
:
function
()
{
let
result
=
`~剩余
${
100
-
this
.
PRECENT_VALUE
}
%内容`
;
if
(
!
this
.
user
)
{
result
=
`
${
result
}
,点击登录后继续阅读`
;
}
else
if
(
!
this
.
user
.
isVip
())
{
result
=
`
${
result
}
为会员章节内容,请前往购买会员`
}
result
=
`
${
result
}
~`
;
return
result
;
},
contentStyle
:
function
()
{
return
{
fontSize
:
this
.
fontSize
}
},
showVIPContent
:
function
()
{
return
(
this
.
user
&&
this
.
user
.
isVip
())
||
this
.
detail
.
isUnlock
}
},
methods
:
{
tapLimitButton
()
{
if
(
!
this
.
user
)
{
showLoginView
()
}
else
if
(
!
this
.
user
.
isVip
())
{
gotoVIPApplyPage
()
}
},
tapVip
()
{
let
isIOS
=
wx
.
getSystemInfoSync
().
platform
;
if
(
isIOS
===
'ios'
)
{
uni
.
showToast
({
title
:
'暂不支持IOS系统'
,
icon
:
'none'
})
return
}
// 展示充值VIP弹框
this
.
$emit
(
'tapVip'
)
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.detail-content
{
paading
:
20rpx
30rpx
;
margin
:
20rpx
30rpx
;
display
:
flex
;
flex-direction
:
column
;
.content-paragraph
{
text-indent
:
1em
;
word-wrap
:
break-word
;
word-break
:
break-all
;
white-space
:
normal
;
line-height
:
1
.5em
;
margin-bottom
:
1em
;
color
:
#333
;
}
.content-paragraph
:last-child
{
margin-bottom
:
0
;
}
.limit-button-box
{
text-indent
:
0
;
height
:
120rpx
;
line-height
:
120rpx
;
text-align
:
center
;
color
:
goldenrod
;
font-size
:
28rpx
;
}
}
</
style
>
\ No newline at end of file
vedio/page-subs/sub_A/book-long-content/components/detail-new-buy.vue
0 → 100644
View file @
528d4299
<
template
>
<view
class=
"detail-buy"
>
<view
class=
"book-card"
>
<view
class=
"line-box"
>
<view
class=
"line"
></view>
<view
class=
"text"
>
全本订阅超优惠
</view>
<view
class=
"line"
></view>
</view>
<view
v-if=
"showBeanOpen==1"
class=
"text-box"
>
<view
class=
"text1"
>
全本特价:
</view>
<view
class=
"text2"
>
{{
bookBeanCount
}}
</view>
<view
class=
"text1"
>
书豆
</view>
</view>
<view
v-if=
"showBeanOpen==1"
class=
"text-box"
style=
"margin-top: 20rpx;"
>
<view
class=
"text1"
>
账户余额:
</view>
<view
class=
"text2"
>
{{
bookAllBeanCount
}}
</view>
<view
class=
"text1"
>
书豆
</view>
</view>
<view
v-if=
"showBeanOpen==1"
class=
"section"
style=
"margin-top: 30rpx;"
>
<button
class=
"btn1"
:disabled=
"loading"
:loading=
"loading"
@
click=
"tapBeanBtn"
>
{{
bookBeanText
}}
</button>
</view>
<view
v-if=
"!isVip() && (showVipOpen==1)"
class=
"section"
style=
"margin-top: 30rpx;"
>
<button
class=
"btn2"
:disabled=
"loading"
:loading=
"loading"
@
click=
"tapVip"
>
开通会员,免费阅读本书
</button>
</view>
</view>
<view
class=
"warn-box"
>
<view
class=
"warn-p"
>
1.目前充值会员暂不支持退款,一经购买不可退换
</view>
<view
class=
"warn-p"
>
2.未满18岁的未成年人需要在监护人主导,同意下进行相关付费操作
</view>
<view
class=
"warn-p"
>
3.充值一般在5分钟内到账,如未到账请提供支付截图在"我的"页面联系客服
</view>
<view
class=
"warn-p"
>
4.之前充值账户请登录后继续阅读
</view>
</view>
</view>
</
template
>
<
script
>
import
Pack
from
"../../../../common/models/Pack.js"
;
import
BookBeanPack
from
"../../../../common/models/BookBeanPack.js"
import
{
showLoginView
,
}
from
"../../../../common/services/userServices.js"
import
{
buyBookWithBookBean
}
from
"../../../../common/services/index.js"
;
import
{
toastHide
,
toastLoading
,
toastMessage
}
from
"../../../../common/utils/toastUtil.js"
;
export
default
{
props
:
{
detail
:
{
type
:
Object
,
default
:
function
()
{
return
{}
}
},
userInfo
:
{
type
:
Object
,
default
:
function
()
{
return
null
}
},
showVipOpen
:
{
type
:
Number
,
default
:
1
},
showBeanOpen
:
{
type
:
Number
,
default
:
1
}
},
data
:
function
()
{
return
{
selectedIndex
:
0
,
loading
:
false
,
imageError
:
true
}
},
computed
:
{
bookBeanText
:
function
()
{
if
(
this
.
userInfo
&&
this
.
detail
)
{
if
(
this
.
userInfo
.
bookLegumes
<
this
.
detail
.
bookLegumes
)
{
return
'余额不足,立即充值'
}
}
return
'全本订阅'
;
},
bookAllBeanCount
:
function
()
{
if
(
this
.
userInfo
)
return
this
.
userInfo
.
bookLegumes
return
0
;
},
bookBeanCount
:
function
()
{
return
this
.
detail
&&
this
.
detail
.
bookLegumes
?
`
${
this
.
detail
.
bookLegumes
}
`
:
"免费"
},
},
mounted
()
{
},
methods
:
{
isVip
()
{
if
(
this
.
userInfo
!=
null
&&
this
.
userInfo
.
memberFlag
)
{
let
cDate
=
new
Date
();
cDate
=
cDate
.
getTime
();
return
this
.
userInfo
.
memberExpirationDate
>=
cDate
;
}
return
false
;
},
tapBeanBtn
()
{
let
isIOS
=
wx
.
getSystemInfoSync
().
platform
;
if
(
isIOS
===
'ios'
)
{
uni
.
showToast
({
title
:
'暂不支持IOS系统'
,
icon
:
'none'
})
return
}
if
(
this
.
userInfo
&&
this
.
detail
)
{
if
(
this
.
userInfo
.
bookLegumes
<
this
.
detail
.
bookLegumes
)
{
this
.
tapBean
()
return
}
}
this
.
tapBuy
()
},
tapVip
()
{
let
isIOS
=
wx
.
getSystemInfoSync
().
platform
;
if
(
isIOS
===
'ios'
)
{
uni
.
showToast
({
title
:
'暂不支持IOS系统'
,
icon
:
'none'
})
return
}
// 展示充值VIP弹框
this
.
$emit
(
'tapVip'
)
},
tapBean
()
{
// 展示充值书豆弹框
this
.
$emit
(
'tapBean'
)
},
tapBuy
()
{
if
(
!
this
.
userInfo
)
{
uni
.
showModal
({
title
:
"登录"
,
content
:
"购买前请前往登录系统"
,
success
:
(
res
)
=>
{
if
(
res
.
confirm
)
{
showLoginView
()
}
}
})
return
;
}
if
(
this
.
userInfo
.
bookLegumes
<
this
.
detail
.
bookLegumes
)
{
uni
.
showModal
({
title
:
"余额不足"
,
content
:
`当前余额:
${
this
.
userInfo
.
bookLegumes
}
, 请前往充值`
,
showCancel
:
false
,
confirmText
:
"知道了"
})
return
;
}
toastLoading
(
"购买中"
);
buyBookWithBookBean
(
this
.
detail
.
id
,
(
success
,
data
)
=>
{
toastHide
();
if
(
success
)
{
this
.
$emit
(
"unlockBook"
)
}
})
},
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.detail-buy
{
display
:
flex
;
flex-direction
:
column
;
.book-card
{
margin
:
20rpx
;
padding
:
20rpx
;
// background: #fdf6f0;
// border-radius: 20rpx;
display
:
flex
;
flex-direction
:
column
;
.section
{
padding
:
0
30rpx
;
display
:
flex
;
flex-direction
:
column
;
.btn1
{
color
:
white
;
background-image
:
linear-gradient
(
90deg
,
pink
,
#DCBD3B
);
width
:
100%
;
height
:
80rpx
;
text-align
:
center
;
border-radius
:
80rpx
;
line-height
:
80rpx
;
}
.btn2
{
color
:
#DCBD3B
;
border
:
#DCBD3B
solid
1rpx
;
width
:
100%
;
text-align
:
center
;
border-radius
:
80rpx
;
height
:
80rpx
;
line-height
:
80rpx
;
}
}
.line-box
{
display
:
flex
;
flex-direction
:
row
;
padding
:
30rpx
;
flex-wrap
:
wrap
;
align-items
:
center
;
.line
{
width
:
30%
;
background-color
:
lightgray
;
height
:
1rpx
;
}
.text
{
text-align
:
center
;
width
:
36%
;
color
:
lightgray
;
font-size
:
26rpx
;
}
}
.text-box
{
display
:
flex
;
flex-direction
:
row
;
.text1
{
font-size
:
24rpx
;
color
:
black
;
}
.text2
{
padding
:
0
10rpx
;
font-size
:
24rpx
;
color
:
#DCBD3B
;
}
}
}
.warn-box
{
color
:
#956244
;
font-size
:
26rpx
;
display
:
flex
;
flex-direction
:
column
;
padding
:
30rpx
;
.warn-p
{
margin-bottom
:
15rpx
;
}
.warn-p
:last-child
{
margin-bottom
:
0
;
}
}
}
</
style
>
\ No newline at end of file
vedio/page-subs/sub_A/book-long-content/components/detail-thumb.vue
0 → 100644
View file @
528d4299
<
template
>
<view
class=
"detail-thumb"
@
click=
"tapThumb"
>
<view
class=
"content"
>
<view
class=
"cover-box item"
>
<image
v-show=
"imageError"
class=
"cover"
src=
"/static/images/image_error.png"
mode=
"aspectFill"
></image>
<image
V-show=
"!imageError"
class=
"cover"
:src=
"detail.avatar"
mode=
"aspectFill"
@
load=
"loadImage"
@
error=
"errorImage"
></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
vedio/page-subs/sub_A/book-long-content/components/detail-warn.vue
0 → 100644
View file @
528d4299
<
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
vedio/page-subs/sub_A/book-long-content/components/recommend-pop.vue
0 → 100644
View file @
528d4299
<
template
>
<uni-popup
ref=
'recommendpop'
type=
"bottom"
:is-mask-click=
'false'
:safe-area=
'false'
@
maskClick=
'tapMask'
>
<view
class=
"setting-box"
>
<view
class=
"section"
>
<view
class=
"title"
>
99%读过这本书的人还在读
</view>
<view
class=
"book-list-item"
v-for=
'(item, index) in dataList'
:key=
'index'
:item=
'item'
@
click=
"tapItem(item)"
>
<view
class=
"cover-box item"
>
<image
v-if=
"item.avatar===''"
class=
"cover"
src=
"/static/images/logo.png"
mode=
"aspectFill"
></image>
<image
v-else
class=
"cover"
:src=
"item.avatar"
mode=
"aspectFill"
></image>
</view>
<view
class=
"c-flex_column"
>
<view
class=
"c-flex_row c-justify_between row"
>
<view
class=
"c-flex_column c-justify_center item"
>
<view
class=
"title2"
>
{{
item
.
title
}}
</view>
</view>
</view>
<view
class=
"c-flex_row row"
>
<view
class=
"c-flex_column c-justify_between content c-flex_1 item"
>
<view
class=
"desc row"
>
{{
item
.
summary
}}
</view>
<view
class=
"c-flex_row c-align_center label-box row"
>
<slot
name=
"footer"
>
<view
class=
"label label-color-1"
v-if=
"item.categoryName!=null&&item.categoryName!=''"
>
{{
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
style=
"display: flex;margin: auto;width: 200rpx;"
>
<button
class=
"btn2"
>
去阅读
</button>
</view>
</view>
</view>
</view>
</uni-popup>
</
template
>
<
script
>
import
SystemInfoMixin
from
"../../../../common/mixins/system-info-mixin.js"
;
import
{
gotoBookContentPage
}
from
'../../../../common/services/page-route'
import
{
getBookRecommendData
}
from
"../services/index.js"
;
import
{
px2rpx
}
from
"../../../../common/utils/util.js"
;
export
default
{
mixins
:
[
SystemInfoMixin
],
props
:
{
show
:
{
type
:
Boolean
,
default
:
false
},
bookId
:
{
type
:
[
Number
,
String
],
default
:
0
}
},
data
:
function
()
{
return
{
showPop
:
false
,
dataList
:
[]
}
},
computed
:
{
safePlacehoderStyle
:
function
()
{
let
height
=
0
;
if
(
this
.
bottomSafeHeight
)
{
height
=
height
+
px2rpx
(
this
.
bottomSafeHeight
)
}
return
{
height
:
`
${
height
}
rpx`
}
}
},
watch
:
{
show
:
function
(
n
)
{
this
.
showPop
=
n
;
},
showPop
:
function
(
n
,
o
)
{
if
(
n
==
o
)
return
;
if
(
n
)
{
this
.
open
();
}
else
{
this
.
close
();
}
}
},
onUnload
()
{
},
mounted
()
{
this
.
requestPackData
();
},
methods
:
{
open
()
{
this
.
$refs
.
recommendpop
.
open
();
},
close
()
{
this
.
$emit
(
'close'
)
this
.
$refs
.
recommendpop
.
close
();
},
tapMask
()
{
this
.
showPop
=
false
;
},
requestPackData
()
{
getBookRecommendData
(
this
.
bookId
,(
success
,
data
)
=>
{
if
(
success
)
{
this
.
dataList
=
data
.
records
;
}
})
},
tapItem
(
item
)
{
// 在C页面内 navigateBack,将返回A页面
uni
.
navigateBack
({
delta
:
2
});
gotoBookContentPage
(
item
.
id
,
item
.
shortis
);
}
}
}
</
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
:
#DCBD3B
;
}
.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
;
}
}
}
.book-list-item
{
display
:
flex
;
flex-direction
:
row
;
padding-top
:
14rpx
;
padding-bottom
:
14rpx
;
.row
{
margin-bottom
:
20rpx
;
}
.row
:last-child
{
margin-bottom
:
0
;
}
.item
{
margin-right
:
20rpx
;
}
.item
:last-child
{
margin-right
:
0
;
}
.title
{
font-size
:
32rpx
;
font-weight
:
700
;
color
:
#333
;
}
.close-button
{
border-radius
:
10rpx
;
border
:
2rpx
solid
#999
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
width
:
40rpx
;
height
:
30rpx
;
position
:
relative
;
.cover
{
position
:
absolute
;
top
:
50%
;
left
:
50%
;
width
:
70rpx
;
height
:
70rpx
;
transform
:
translate
(
-50%
,
-50%
);
z-index
:
2
;
background
:
transparent
;
}
}
.desc
{
overflow
:
hidden
;
text-overflow
:
ellipsis
;
display
:
-
webkit-box
;
-webkit-line-clamp
:
2
;
-webkit-box-orient
:
vertical
;
font-size
:
26rpx
;
color
:
#999
}
.label-box
{
flex-wrap
:
wrap
;
.label
{
padding
:
5rpx
10rpx
;
font-size
:
20rpx
;
margin-right
:
20rpx
;
border-radius
:
10rpx
;
}
.label-color-1
{
background
:
#faefe6
;
color
:
#cc6008
;
}
.label-color-2
{
color
:
#3d99fd
;
background
:
#d8ebff
;
}
.label-color-3
{
background
:
#ff8787
;
color
:
#ff3737
;
}
}
}
.cover-box
{
.cover
{
width
:
150rpx
;
height
:
200rpx
;
border-radius
:
15rpx
;
}
}
.title2
{
font-size
:
32rpx
;
font-weight
:
700
;
color
:
#333
;
}
.btn2
{
color
:
#d98c5c
;
border
:
#DCBD3B
solid
1rpx
;
width
:
140rpx
;
font-size
:
24rpx
;
text-align
:
center
;
border-radius
:
80rpx
;
height
:
40rpx
;
line-height
:
40rpx
;
}
</
style
>
\ No newline at end of file
vedio/page-subs/sub_A/book-long-content/components/setting-pop.vue
0 → 100644
View file @
528d4299
<
template
>
<uni-popup
ref=
'pop'
type=
"bottom"
:is-mask-click=
'false'
:safe-area=
'false'
@
change=
'change'
>
<view
class=
"setting-box"
>
<view
class=
"row"
>
<view
class=
"title"
>
字体大小
</view>
<view
class=
"zone"
>
<view
class=
"c-flex_1"
>
<slider
min=
"14"
max=
"24"
step=
'1'
:value=
'currentContentFormat.fontSize'
:show-value=
"true"
@
change=
'changeFontSize'
>
</slider>
</view>
</view>
</view>
<view
class=
"row"
>
<view
class=
"title"
>
背景颜色
</view>
<view
class=
"zone"
>
<view
class=
"color-item"
:class=
"
{'selected-color': item.value==currentContentFormat.backgroundColor}"
:style="[item.style]" v-for='(item, index) in colorList' :key="index"
@click="chooseColor(item.value)">
</view>
</view>
</view>
<view
class=
"safe-placeholder"
:style=
"[safePlacehoderStyle]"
>
</view>
</view>
</uni-popup>
</
template
>
<
script
>
import
SystemInfoMixin
from
"../../../../common/mixins/system-info-mixin.js"
;
import
{
px2rpx
}
from
"../../../../common/utils/util.js"
;
import
{
saveContentFormat
,
readContentFormat
}
from
"../services/index.js"
export
default
{
mixins
:
[
SystemInfoMixin
],
props
:
{
show
:
{
type
:
Boolean
,
default
:
false
}
},
data
:
function
()
{
return
{
showPop
:
false
,
colorList
:
[],
currentContentFormat
:
{},
}
},
computed
:
{
safePlacehoderStyle
:
function
()
{
let
height
=
0
;
if
(
this
.
bottomSafeHeight
)
{
height
=
height
+
px2rpx
(
this
.
bottomSafeHeight
)
}
return
{
height
:
`
${
height
}
rpx`
}
},
},
watch
:
{
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
()
},
methods
:
{
open
()
{
this
.
$refs
.
pop
.
open
();
},
close
()
{
this
.
$emit
(
'close'
)
this
.
$refs
.
pop
.
close
();
},
change
(
e
)
{
if
(
this
.
showPop
==
e
.
show
)
return
;
this
.
showPop
=
e
.
show
},
initColorList
()
{
this
.
colorList
=
[
"#fff"
,
"#e7e7e7"
,
"#d4e0c6"
,
"#ccd8e4"
,
"#f9d4d4"
,
"#b1b1b1"
].
map
(
item
=>
{
return
{
style
:
{
background
:
item
},
value
:
item
}
})
},
changeFontSize
(
e
)
{
let
fontSize
=
e
.
detail
.
value
;
this
.
currentContentFormat
.
fontSize
=
fontSize
;
saveContentFormat
(
this
.
currentContentFormat
);
},
chooseColor
(
color
)
{
this
.
currentContentFormat
.
backgroundColor
=
color
;
saveContentFormat
(
this
.
currentContentFormat
);
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.setting-box
{
display
:
flex
;
flex-direction
:
column
;
padding
:
20rpx
;
background
:
#fff
;
border-top-left-radius
:
15rpx
;
border-top-right-radius
:
15rpx
;
.row
{
display
:
flex
;
flex-direction
:
column
;
justify-content
:
center
;
padding
:
20rpx
;
.title
{
font-size
:
30rpx
;
font-weight
:
700
;
margin-bottom
:
20rpx
;
}
.zone
{
display
:
flex
;
flex-direction
:
row
;
align-items
:
center
;
justify-content
:
space-around
;
.color-item
{
width
:
80rpx
;
height
:
80rpx
;
border-radius
:
40rpx
;
border
:
2rpx
solid
#999
;
}
.selected-color
{
width
:
100rpx
;
height
:
100rpx
;
border-radius
:
50rpx
;
border
:
5rpx
solid
#ff2525
;
}
}
}
}
</
style
>
\ No newline at end of file
vedio/page-subs/sub_A/book-long-content/components/vip-pop.vue
0 → 100644
View file @
528d4299
<
template
>
<uni-popup
ref=
'vippop'
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 packList'
:key='index' @click="choosePack(item, index)">
<view
class=
"name row"
>
{{
item
.
title
}}
</view>
<view
class=
"price row"
>
¥
{{
item
.
price
}}
</view>
<view
class=
"origin row"
v-if=
'item.originalPrice'
>
原价:
{{
item
.
originalPrice
}}
</view>
<view
class=
"cut-down"
v-if=
'item.cutDown'
>
立省
{{
item
.
cutDown
}}
元
</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
Pack
from
"../../../../common/models/Pack.js"
;
import
{
getPackData
,
getOpenId
,
getPayInfo
}
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
,
packList
:
[],
selectedIndex
:
0
,
loading
:
false
,
userInfo
:
null
}
},
computed
:
{
safePlacehoderStyle
:
function
()
{
let
height
=
0
;
if
(
this
.
bottomSafeHeight
)
{
height
=
height
+
px2rpx
(
this
.
bottomSafeHeight
)
}
return
{
height
:
`
${
height
}
rpx`
}
},
},
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
.
refrehsPackData
();
},
methods
:
{
open
()
{
this
.
$refs
.
vippop
.
open
();
},
close
()
{
this
.
$emit
(
'close'
)
this
.
$refs
.
vippop
.
close
();
},
tapMask
()
{
this
.
showPop
=
false
;
},
refrehsPackData
()
{
getPackData
((
success
,
data
)
=>
{
this
.
packList
=
data
.
map
(
item
=>
{
return
new
Pack
(
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
.
packList
[
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
;
}
})
}
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
vedio/page-subs/sub_A/book-long-content/models/BookDetail.js
0 → 100644
View file @
528d4299
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
vedio/page-subs/sub_A/book-long-content/models/CatalogueList.js
0 → 100644
View file @
528d4299
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
vedio/page-subs/sub_A/book-long-content/models/ContentFormat.js
0 → 100644
View file @
528d4299
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
vedio/page-subs/sub_A/book-long-content/services/index.js
0 → 100644
View file @
528d4299
import
{
addNormalNotificationObserver
,
postNotification
,
removeNotificationObserver
}
from
"../../../../common/utils/notificationCenter"
;
import
{
readStorage
,
saveStorage
}
from
"../../../../common/utils/storageUtil"
;
import
ContentFormat
from
"../models/ContentFormat"
;
import
{
apiGET
,
apiPOST
}
from
"../../../../common/utils/apiRequest.js"
import
CatalogueList
from
"../models/CatalogueList"
;
/** 获取文章详情
* @param {Object} bookId
* @param {Object} callback
*/
function
getBookDetailData
(
bookId
,
callback
)
{
apiPOST
({
url
:
`/book/info`
,
data
:
{
id
:
bookId
},
callback
})
}
/** 获取章节数据
* @param {Object} bookId
* @param {Object} chapterId
* @param {Object} callback
*/
function
getChapterinfoData
(
bookId
,
chapterId
,
callback
)
{
apiPOST
({
url
:
`/book/chapterinfo`
,
data
:
{
articleId
:
bookId
,
chapterId
:
chapterId
,
},
callback
})
}
/** 获取推荐文章
* @param {Object} bookId
* @param {Object} callback
*/
function
getBookRecommendData
(
bookId
,
callback
)
{
apiPOST
({
url
:
`/book/recommend`
,
data
:
{
id
:
bookId
},
callback
})
}
/** 添加阅读记录
* @param {Object} bookId
* @param {Object} callback
*/
function
addReadRecord
(
bookId
,
callback
)
{
apiPOST
({
url
:
`/book/addReadRecord`
,
data
:
{
articleId
:
bookId
},
callback
})
}
// 样式设置
const
KEY_STORAGE_LONG_CONTENT_FORMAT
=
"KEY_STORAGE_LONG_CONTENT_FORMAT"
;
const
KEY_NOTIFICATION_LONG_CONTENT_FORMAT_CHANGE
=
"KEY_NOTIFICATION_LONG_CONTENT_FORMAT_CHANGE"
;
function
saveContentFormat
(
format
)
{
let
result
=
readContentFormat
();
Object
.
keys
(
format
).
forEach
(
key
=>
{
let
value
=
format
[
key
];
result
[
key
]
=
value
||
result
[
key
];
})
saveStorage
(
KEY_STORAGE_LONG_CONTENT_FORMAT
,
result
);
notifyContentFormatChange
(
new
ContentFormat
(
result
));
}
function
readContentFormat
(
id
)
{
let
result
=
readStorage
(
KEY_STORAGE_LONG_CONTENT_FORMAT
);
if
(
result
)
{
result
=
new
ContentFormat
(
result
);
}
else
{
result
=
new
ContentFormat
({
fontSize
:
17
,
backgroundColor
:
"#fff"
,
catalogueList
:
[]
// 章节列表
})
}
return
result
;
}
function
notifyContentFormatChange
(
format
)
{
postNotification
(
KEY_NOTIFICATION_LONG_CONTENT_FORMAT_CHANGE
,
format
);
}
function
watchContentFormatChange
(
fn
,
observer
)
{
if
(
typeof
fn
==
'function'
)
fn
.
call
(
observer
,
readContentFormat
());
addNormalNotificationObserver
(
KEY_NOTIFICATION_LONG_CONTENT_FORMAT_CHANGE
,
(
data
)
=>
{
if
(
typeof
fn
==
'function'
)
fn
.
call
(
observer
,
data
);
},
observer
)
}
function
removeContentFormatChangeWatch
(
observer
)
{
removeNotificationObserver
(
KEY_NOTIFICATION_LONG_CONTENT_FORMAT_CHANGE
,
observer
);
}
module
.
exports
=
{
getBookDetailData
,
getBookRecommendData
,
addReadRecord
,
getChapterinfoData
,
/**
* content format
*/
saveContentFormat
,
readContentFormat
,
notifyContentFormatChange
,
watchContentFormatChange
,
removeContentFormatChangeWatch
}
\ No newline at end of file
vedio/page-subs/sub_A/book-search/components/recommond-item.vue
View file @
528d4299
...
...
@@ -45,7 +45,7 @@
},
methods
:
{
tapItem
()
{
gotoBookContentPage
(
this
.
item
.
id
);
gotoBookContentPage
(
this
.
item
.
id
,
this
.
item
.
shortis
);
},
loadImage
()
{
this
.
imageError
=
false
...
...
vedio/page-subs/sub_A/book-search/components/search-result.vue
View file @
528d4299
<
template
>
<c-list
ref=
"list"
flag=
'search'
method=
"POST"
:needLogin=
"needLogin"
:height=
"height"
:url=
'requestUrl'
:param=
'requestParam'
@
change=
'changeData'
>
<c-list
ref=
"list"
flag=
'search'
method=
"POST"
:needLogin=
"needLogin"
:height=
"height"
:url=
'requestUrl'
:param=
'requestParam'
@
change=
'changeData'
>
<book-list-item
v-for=
'(item, index) in dataList'
:key=
'index'
:item=
'item'
:showClose=
"false"
@
tapItem=
'tapItem($event, index)'
>
</book-list-item>
...
...
@@ -79,7 +79,7 @@
})
},
tapItem
(
e
,
index
)
{
gotoBookContentPage
(
e
.
detail
.
data
.
id
)
gotoBookContentPage
(
e
.
detail
.
data
.
id
,
e
.
detail
.
data
.
id
)
},
}
}
...
...
vedio/pages.json
View file @
528d4299
...
...
@@ -69,6 +69,13 @@
"enablePullDownRefresh"
:
true
}
},
{
"path"
:
"book-long-content/book-long-content"
,
"style"
:
{
"navigationBarTitleText"
:
"阅读"
,
"enablePullDownRefresh"
:
true
}
},
{
"path"
:
"book-cover/book-cover"
,
"style"
:
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment