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
dbf68494
Commit
dbf68494
authored
Jun 24, 2024
by
jyx
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
代码优化
parent
abb53a01
Changes
35
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
146 additions
and
5375 deletions
+146
-5375
page-route.js
vedio/common/services/page-route.js
+1
-45
userServices.js
vedio/common/services/userServices.js
+3
-4
ad-popup.vue
vedio/components/ad-popup/ad-popup.vue
+0
-137
alert.vue
vedio/components/alert/alert.vue
+0
-157
divider.vue
vedio/components/divider/divider.vue
+0
-30
number-box.vue
vedio/components/number-box/number-box.vue
+0
-163
post-list.vue
vedio/components/post-list/post-list.vue
+0
-371
q-button.vue
vedio/components/q-button/q-button.vue
+0
-77
send-code.vue
vedio/components/send-code/send-code.vue
+0
-128
service-img-dialog.vue
vedio/components/service-img-dialog/service-img-dialog.vue
+0
-84
time-down.vue
vedio/components/time-down/time-down.vue
+0
-67
choose-and-upload-file.js
vedio/components/uni-file-picker/choose-and-upload-file.js
+0
-224
uni-file-picker.vue
vedio/components/uni-file-picker/uni-file-picker.vue
+0
-672
upload-file.vue
vedio/components/uni-file-picker/upload-file.vue
+0
-327
upload-image.vue
vedio/components/uni-file-picker/upload-image.vue
+0
-286
utils.js
vedio/components/uni-file-picker/utils.js
+0
-109
verify-code.vue
vedio/components/verify-code/verify-code.vue
+0
-289
video-loading.vue
vedio/components/video-loading/video-loading.vue
+0
-96
common.js
vedio/mixins/common.js
+133
-175
history-item.vue
.../page-subs/sub_A/read-history/components/history-item.vue
+0
-158
ReadHistory.js
vedio/page-subs/sub_A/read-history/models/ReadHistory.js
+0
-7
read-history.vue
vedio/page-subs/sub_A/read-history/read-history.vue
+0
-114
book-bean-detail.vue
vedio/page-subs/sub_B/book-bean-detail/book-bean-detail.vue
+0
-182
book-bean-header.vue
...bs/sub_B/book-bean-detail/components/book-bean-header.vue
+0
-140
BookBeanRecordItem.js
...-subs/sub_B/book-bean-detail/models/BookBeanRecordItem.js
+0
-18
book-bean-recharge.vue
...page-subs/sub_B/book-bean-recharge/book-bean-recharge.vue
+0
-283
feedback.vue
vedio/page-subs/sub_B/feedback/feedback.vue
+0
-53
message.vue
vedio/page-subs/sub_B/message/message.vue
+0
-70
read-preference.vue
vedio/page-subs/sub_B/read-preference/read-preference.vue
+0
-144
edit-input-pop.vue
...o/page-subs/sub_B/user-edit/components/edit-input-pop.vue
+0
-126
index.js
vedio/page-subs/sub_B/user-edit/services/index.js
+0
-70
user-edit.vue
vedio/page-subs/sub_B/user-edit/user-edit.vue
+0
-202
vip-apply.vue
vedio/page-subs/sub_B/vip-apply/vip-apply.vue
+0
-313
pages.json
vedio/pages.json
+2
-48
loading.vue
vedio/pages/loading.vue
+7
-6
No files found.
vedio/common/services/page-route.js
View file @
dbf68494
...
@@ -41,17 +41,10 @@ function gotoBookCoverPage(bookId) {
...
@@ -41,17 +41,10 @@ function gotoBookCoverPage(bookId) {
})
})
}
}
// 阅读历史
function
gotoReadHistoryPage
()
{
uni
.
navigateTo
({
url
:
`/page-subs/sub_A/read-history/read-history`
})
}
// vip申请
// vip申请
function
gotoVIPApplyPage
()
{
function
gotoVIPApplyPage
()
{
uni
.
navigateTo
({
uni
.
navigateTo
({
url
:
`/page
-subs/sub_B/vip-apply/vip-appl
y`
,
url
:
`/page
sA//vipPay/vipPa
y`
,
})
})
}
}
...
@@ -67,50 +60,13 @@ function gotoUserEditPage(userInfo) {
...
@@ -67,50 +60,13 @@ function gotoUserEditPage(userInfo) {
})
})
}
}
// 消息
function
gotoMessagePage
(
type
=
ENUM_MESSAGE_PAGE_TYPE
.
SYS
.
value
)
{
uni
.
navigateTo
({
url
:
`/page-subs/sub_B/message/message`
,
success
:
(
res
)
=>
{
res
.
eventChannel
.
emit
(
"openMessagePage"
,
{
type
})
}
})
}
// 阅读喜好
function
gotoReadPreferencePage
()
{
uni
.
navigateTo
({
url
:
`/page-subs/sub_B/read-preference/read-preference`
,
})
}
// 书豆明细
function
gotoBookBeanDetailPage
()
{
uni
.
navigateTo
({
url
:
`/page-subs/sub_B/book-bean-detail/book-bean-detail`
})
}
// 书豆充值
function
gotoBookBeanRechargePage
()
{
uni
.
navigateTo
({
url
:
`/page-subs/sub_B/book-bean-recharge/book-bean-recharge`
})
}
module
.
exports
=
{
module
.
exports
=
{
/** sub_A */
/** sub_A */
gotoBookSearchPage
,
gotoBookSearchPage
,
gotoBookContentPage
,
gotoBookContentPage
,
gotoBookCoverPage
,
gotoBookCoverPage
,
gotoReadHistoryPage
,
/** sub_B */
/** sub_B */
gotoVIPApplyPage
,
gotoVIPApplyPage
,
gotoUserEditPage
,
gotoUserEditPage
,
gotoMessagePage
,
gotoReadPreferencePage
,
gotoBookBeanDetailPage
,
gotoBookBeanRechargePage
}
}
\ No newline at end of file
vedio/common/services/userServices.js
View file @
dbf68494
...
@@ -148,7 +148,7 @@ function postPhone(data, callback) {
...
@@ -148,7 +148,7 @@ function postPhone(data, callback) {
function
requestToken
(
data
,
callback
)
{
function
requestToken
(
data
,
callback
)
{
let
url
=
`
${
config
[
"BASE_URL"
]}
/user/ttLogin`
;
let
url
=
`
${
config
[
"BASE_URL"
]}
/user/ttLogin`
;
let
header
=
{
let
header
=
{
pkg
n
ame
:
PAKEAGE_NAME
,
pkg
N
ame
:
PAKEAGE_NAME
,
token
:
``
token
:
``
}
}
uni
.
request
({
uni
.
request
({
...
@@ -168,7 +168,6 @@ function requestToken(data, callback) {
...
@@ -168,7 +168,6 @@ function requestToken(data, callback) {
// 请求用户数据
// 请求用户数据
function
requestUserInfo
(
callback
)
{
function
requestUserInfo
(
callback
)
{
let
url
=
`
${
config
[
'BASE_URL'
]}
/user/baseMsg`
;
let
url
=
`
${
config
[
'BASE_URL'
]}
/user/baseMsg`
;
let
header
=
{}
let
header
=
{}
let
uniChannel
=
'wechat'
;
let
uniChannel
=
'wechat'
;
...
@@ -181,8 +180,8 @@ function requestUserInfo(callback) {
...
@@ -181,8 +180,8 @@ function requestUserInfo(callback) {
// #endif
// #endif
Object
.
assign
(
header
,
{
Object
.
assign
(
header
,
{
token
:
uni
.
getStorageSync
(
'token'
),
token
:
readToken
(
),
pkgName
:
app
.
globalData
.
pkgName
,
pkgName
:
PAKEAGE_NAME
,
proChannel
:
uniChannel
proChannel
:
uniChannel
})
})
...
...
vedio/components/ad-popup/ad-popup.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view>
<uni-popup
type=
"center"
ref=
"adPop"
:maskClick=
"false"
:isMaskClick=
"false"
>
<view
class=
"container"
>
<!--
<view
class=
"ad-view"
>
<ad
:unit-id=
"adUnitId"
@
load=
"onload"
@
close=
"onclose"
@
error=
"onerror"
></ad>
</view>
-->
<view
class=
"content"
>
<text
class=
"title"
>
恭喜你,获得免费看剧名额
</text>
<text
class=
"button"
@
click=
"handleClose"
>
看视频免费解锁1集
</text>
<text
class=
"downtext"
>
{{
countDown
}}
s后自动进入广告,阅读完成解锁第
{{
vedioIndex
+
1
}}
集剧情
</text>
</view>
</view>
</uni-popup>
</view>
</
template
>
<
script
>
import
{
EXPRESS_ID
}
from
"@/utils/adConstant.js"
export
default
{
name
:
'adPopup'
,
props
:
{
show
:
{
type
:
Boolean
,
default
:
false
,
},
vedioIndex
:
{
type
:
[
Number
,
String
],
default
:
0
}
},
data
()
{
return
{
adUnitId
:
EXPRESS_ID
,
countDown
:
3
,
};
},
methods
:
{
handleShow
()
{
this
.
$refs
.
adPop
.
open
(
'center'
);
this
.
startCountdown
()
},
startCountdown
()
{
let
that
=
this
;
var
countDownSeconds
=
3
that
.
countDown
=
countDownSeconds
const
timer
=
setInterval
(()
=>
{
if
(
countDownSeconds
>
0
)
{
that
.
countDown
=
countDownSeconds
countDownSeconds
--
}
else
{
clearInterval
(
timer
)
that
.
handleClose
()
}
},
1000
)
},
handleClose
()
{
this
.
$refs
.
adPop
.
close
(
'center'
);
this
.
$emit
(
'close'
);
},
onload
(
e
)
{
console
.
log
(
"onload"
);
},
onclose
(
e
)
{
console
.
log
(
"onclose: "
+
e
.
detail
);
},
onerror
(
e
)
{
console
.
log
(
"onerror: "
+
e
.
detail
.
errCode
+
" message:: "
+
e
.
detail
.
errMsg
);
}
},
watch
:
{
show
:
{
handler
:
function
(
newVal
,
oldVal
)
{
if
(
newVal
)
{
this
.
handleShow
();
}
},
immediate
:
true
}
}
};
</
script
>
<
style
lang=
"scss"
>
.container
{
width
:
600rpx
;
height
:
800rpx
;
position
:
relative
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
center
;
}
.ad-view
{
width
:
600rpx
;
border-radius
:
20rpx
;
// background-color: white;
margin-bottom
:
10px
;
}
.content
{
border-radius
:
20rpx
;
background-color
:
white
;
display
:
flex
;
width
:
600rpx
;
padding
:
30rpx
0
;
flex-direction
:
column
;
align-items
:
center
;
.title
{
color
:
black
;
font-size
:
40rpx
;
font-weight
:
bold
;
margin-bottom
:
30rpx
;
}
.button
{
margin
:
20rpx
20rpx
;
border-radius
:
10rpx
;
background-color
:
orange
;
color
:
white
;
font-size
:
36rpx
;
}
.downtext
{
color
:
darkgray
;
font-size
:
26rpx
;
}
}
</
style
>
\ No newline at end of file
vedio/components/alert/alert.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view>
<view
:class=
"'alert-mask ' + (showClone ? 'alert-mask-active' : '')"
@
click=
"handleClose"
@
click
.
stop
.
prevent=
""
></view>
<view
:class=
"'alert ' + (showClone ? 'alert-active' : '')"
>
>
<icons
class=
"alert-close"
icon=
"close"
@
click=
"handleClose"
color=
"white"
></icons>
<image
v-if=
"isMarkImg"
class=
"alert-mask-img"
src=
"../../static/alert-mask.png"
mode=
"scaleToFill"
></image>
<view
class=
"alert-content"
>
<image
class=
"alert-title"
:src=
"title"
mode=
"scaleToFill"
></image>
<view
class=
"alert-wrap"
><slot></slot></view>
<button
v-if=
"isConfirmShow"
class=
"alert-btn"
:style=
"'color:' + color"
@
click=
"handleSuccess"
>
{{
confirmText
}}
</button>
</view>
</view>
</view>
</
template
>
<
script
>
export
default
{
props
:
{
title
:
{
type
:
String
,
default
:
''
},
show
:
{
type
:
Boolean
,
default
:
false
},
confirmText
:
{
type
:
String
,
default
:
'确定'
},
isConfirmShow
:
{
type
:
Boolean
,
default
:
true
},
isMarkImg
:
{
type
:
Boolean
,
default
:
true
},
color
:
{
type
:
String
,
default
:
'#008cfb'
}
},
data
()
{
return
{
showClone
:
false
};
},
methods
:
{
handleSuccess
()
{
this
.
handleClose
();
this
.
$emit
(
'success'
);
},
handleClose
()
{
this
.
showClone
=
false
;
this
.
$emit
(
'close'
);
}
},
watch
:
{
show
:
{
handler
:
function
(
newVal
,
oldVal
)
{
console
.
log
(
newVal
);
this
.
showClone
=
newVal
;
},
immediate
:
true
}
}
};
</
script
>
<
style
lang=
"scss"
>
.alert
{
position
:
fixed
;
z-index
:
1002
;
left
:
75rpx
;
right
:
75rpx
;
top
:
50%
;
padding
:
0
;
display
:
none
;
transform
:
translate
(
0
,
-50%
);
backface-visibility
:
hidden
;
&
-content
{
border-radius
:
16rpx
;
overflow
:
hidden
;
background-color
:
#fff
;
}
&
-mask
{
position
:
fixed
;
width
:
100%
;
height
:
100%
;
top
:
0
;
left
:
0
;
z-index
:
999
;
background-color
:
rgba
(
0
,
0
,
0
,
0
.8
);
opacity
:
0
;
transform
:
scale3d
(
1
,
1
,
0
);
transition
:
all
0
.3s
;
&
-active
{
opacity
:
1
;
transform
:
scale3d
(
1
,
1
,
1
);
}
&
-img
{
position
:
absolute
;
z-index
:
5
;
width
:
110%
;
height
:
110%
;
left
:
-5%
;
top
:
-5%
;
}
}
&
-active
{
display
:
block
;
}
&
-close
{
position
:
absolute
;
top
:
24rpx
;
padding
:
30rpx
;
right
:
0
;
z-index
:
10
;
}
&
-btn
{
background-color
:
white
;
width
:
100%
!
important
;
margin
:
0
!
important
;
text-align
:
center
;
padding
:
0
;
font-size
:
32rpx
;
line-height
:
110rpx
;
background
:
transparent
;
outline
:
none
;
z-index
:
10
;
&
.button-hover
{
background
:
#ececec
!
important
;
}
}
&
-title
{
width
:
100%
;
height
:
138rpx
;
}
&
-wrap
{
padding
:
45rpx
66rpx
;
border-bottom
:
1rpx
solid
#ddd
;
}
}
</
style
>
vedio/components/divider/divider.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view
class=
"divider flex"
><slot></slot></view>
</
template
>
<
script
>
export
default
{
name
:
'Divider'
};
</
script
>
<
style
lang=
"scss"
>
@import
'@/scss/uni.scss'
;
.divider
{
font-size
:
24rpx
;
color
:
#868686
;
&
:
:
before
,
&::
after
{
content
:
''
;
background-color
:
#868686
;
height
:
1rpx
;
flex
:
1
;
}
&
:
:
before
{
margin-right
:
28rpx
;
}
&
:
:
after
{
margin-left
:
28rpx
;
}
}
</
style
>
vedio/components/number-box/number-box.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view
class=
"number-box"
>
<view
@
click=
"_calcValue('minus')"
class=
"number-box-btns"
:class=
"
{ 'number-box-disabled': inputValue
<
=
min
||
disabled
}"
>
<icons
icon=
"minus"
:color=
"inputValue
<
=
min
||
disabled
?
'#
868686
'
:
'#
299FEF
'"
size=
"40"
/>
</view>
<input
:disabled=
"disabled"
@
focus=
"_onFocus"
@
blur=
"_onBlur"
class=
"number-box-input"
type=
"number"
v-model=
"inputValue"
/>
<view
@
click=
"_calcValue('plus')"
class=
"number-box-btns"
><icons
icon=
"plus"
:color=
"inputValue >= max || disabled ? '#868686' : '#299FEF'"
size=
"40"
/></view>
</view>
</
template
>
<
script
>
/**
* NumberBox 数字输入框
* @description 带加减按钮的数字输入框
* @tutorial https://ext.dcloud.net.cn/plugin?id=31
* @property {Number} value 输入框当前值
* @property {Number} min 最小值
* @property {Number} max 最大值
* @property {Number} step 每次点击改变的间隔大小
* @property {String} color 字体颜色(前景色)
* @property {Boolean} disabled = [true|false] 是否为禁用状态
* @event {Function} change 输入框值改变时触发的事件,参数为输入框当前的 value
* @event {Function} focus 输入框聚焦时触发的事件,参数为 event 对象
* @event {Function} blur 输入框失焦时触发的事件,参数为 event 对象
*/
export
default
{
name
:
'NumberBox'
,
emits
:
[
'change'
,
'input'
,
'update:modelValue'
,
'blur'
,
'focus'
],
props
:
{
value
:
{
type
:
[
Number
,
String
],
default
:
1
},
modelValue
:
{
type
:
[
Number
,
String
],
default
:
1
},
min
:
{
type
:
Number
,
default
:
0
},
max
:
{
type
:
Number
,
default
:
100
},
step
:
{
type
:
Number
,
default
:
1
},
disabled
:
{
type
:
Boolean
,
default
:
false
}
},
data
()
{
return
{
inputValue
:
0
};
},
watch
:
{
value
(
val
)
{
this
.
inputValue
=
+
val
;
},
modelValue
(
val
)
{
this
.
inputValue
=
+
val
;
}
},
created
()
{
if
(
this
.
value
===
1
)
{
this
.
inputValue
=
+
this
.
modelValue
;
}
if
(
this
.
modelValue
===
1
)
{
this
.
inputValue
=
+
this
.
value
;
}
},
methods
:
{
_calcValue
(
type
)
{
if
(
this
.
disabled
)
{
return
;
}
const
scale
=
this
.
_getDecimalScale
();
let
value
=
this
.
inputValue
*
scale
;
let
step
=
this
.
step
*
scale
;
if
(
type
===
'minus'
)
{
value
-=
step
;
if
(
value
<
this
.
min
*
scale
)
{
return
;
}
if
(
value
>
this
.
max
*
scale
)
{
value
=
this
.
max
*
scale
;
}
}
if
(
type
===
'plus'
)
{
value
+=
step
;
if
(
value
>
this
.
max
*
scale
)
{
return
;
}
if
(
value
<
this
.
min
*
scale
)
{
value
=
this
.
min
*
scale
;
}
}
this
.
inputValue
=
(
value
/
scale
).
toFixed
(
String
(
scale
).
length
-
1
);
this
.
$emit
(
'change'
,
+
this
.
inputValue
);
// TODO vue2 兼容
this
.
$emit
(
'input'
,
+
this
.
inputValue
);
// TODO vue3 兼容
this
.
$emit
(
'update:modelValue'
,
+
this
.
inputValue
);
},
_getDecimalScale
()
{
let
scale
=
1
;
// 浮点型
if
(
~~
this
.
step
!==
this
.
step
)
{
scale
=
Math
.
pow
(
10
,
String
(
this
.
step
).
split
(
'.'
)[
1
].
length
);
}
return
scale
;
},
_onBlur
(
event
)
{
this
.
$emit
(
'blur'
,
event
);
let
value
=
event
.
detail
.
value
;
if
(
!
value
)
{
// this.inputValue = 0;
return
;
}
value
=
+
value
;
if
(
value
>
this
.
max
)
{
value
=
this
.
max
;
}
else
if
(
value
<
this
.
min
)
{
value
=
this
.
min
;
}
const
scale
=
this
.
_getDecimalScale
();
this
.
inputValue
=
value
.
toFixed
(
String
(
scale
).
length
-
1
);
this
.
$emit
(
'change'
,
+
this
.
inputValue
);
this
.
$emit
(
'input'
,
+
this
.
inputValue
);
},
_onFocus
(
event
)
{
this
.
$emit
(
'focus'
,
event
);
}
}
};
</
script
>
<
style
lang=
"scss"
>
.number-box
{
display
:
inline-flex
;
align-items
:
center
;
margin-right
:
-16rpx
;
&
-btns
{
line-height
:
1
;
vertical-align
:
bottom
;
display
:
inline-block
;
padding
:
16rpx
;
cursor
:
pointer
;
}
&
-input
{
margin
:
0
4rpx
;
width
:
50rpx
;
text-align
:
center
;
color
:
black
;
}
}
</
style
>
vedio/components/post-list/post-list.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view>
<block
v-for=
"(item, index) in list"
:key=
"index"
>
<view
@
click=
"jump(item)"
>
<view
class=
"post-item"
>
<view
class=
"post-item-top-user"
>
<view
@
click
.
stop=
"toUcenter(item.uid)"
>
<u-avatar
class=
"avatar"
:src=
"item.userInfo.avatarUrl"
:show-level=
"item.userInfo.type == 1"
level-bg-color=
"#8072f3"
></u-avatar>
</view>
<view
class=
"center"
>
<view
style=
"display: flex;align-items: center;"
>
<text
v-if=
"item.userInfo.type == 1"
class=
"official"
>
官方
</text>
<text
v-if=
"item.userInfo.vip_expire_time > timestamp"
style=
"color: red;"
class=
"username"
>
{{
item
.
userInfo
.
nickName
.
substring
(
0
,
12
)
}}
</text>
<text
v-else
class=
"username"
>
{{
item
.
userInfo
.
nickName
.
substring
(
0
,
12
)
}}
</text>
</view>
<view>
<text
class=
"time"
>
{{
item
.
createTime
|
timeFrom
}}
</text>
</view>
</view>
<view
v-if=
"item.type==0&&(index
<3
)"
v-for=
"index2 in (3-index)>0?(3-index):0"
>
<image
style=
"width: 30rpx;margin-right: 10rpx;"
mode=
"widthFix"
src=
"../../static/moments/ic_fire.png"
></image>
</view>
</view>
<view
class=
"post-content"
>
<rich-text
class=
"post-text"
:nodes=
"item.content"
></rich-text>
<!-- 帖子类型 -->
<block
v-if=
"(item.mediaType==0||item.mediaType==1)&&item.media!=null"
>
<!--一张图片-->
<block
v-if=
"item.media.length==1"
>
<image
:lazy-load=
"true"
mode=
"aspectFill"
class=
"img-style-1"
:src=
"item.media[0]"
@
tap
.
stop=
"previewImage(item.media[0], item.media, item.integral, item.id)"
></image>
</block>
<!--二张图片-->
<block
v-if=
"item.media.length==2"
>
<view
class=
"img-style-2"
>
<image
:lazy-load=
"true"
v-for=
"(mediaItem, index2) in item.media"
:key=
"index2"
@
tap
.
stop=
"previewImage(mediaItem, item.media, item.integral, item.id)"
mode=
"aspectFill"
:src=
"mediaItem"
></image>
</view>
</block>
<!--三张以上图片-->
<block
v-if=
"item.media.length>2"
>
<view
class=
"img-style-3"
>
<image
:lazy-load=
"true"
v-for=
"(mediaItem, index2) in item.media"
:key=
"index2"
@
tap
.
stop=
"previewImage(mediaItem, item.media, item.integral, item.id)"
mode=
"aspectFill"
:src=
"mediaItem"
></image>
</view>
</block>
</block>
<!-- 视频 -->
<view
class=
"video-wrap"
v-if=
"item.mediaType==2&&item.media.length>0"
>
<image
@
tap
.
stop=
"previewMedia(item.media[0],item.userLike,item.likes,item.id)"
class=
"icon"
src=
"../../static/moments/play.png"
></image>
<image
mode=
"aspectFill"
:src=
"item.media[0] + '?x-oss-process=video/snapshot,t_0,f_jpg'"
>
</image>
</view>
</view>
<!-- 底部 -->
<view
class=
"p-footer"
>
<view
class=
"p-item "
>
<button
@
click
.
stop=
"showShares(index)"
class=
"u-reset-button"
open-type=
"share"
>
<u-icon
name=
"share-square"
size=
"24"
></u-icon>
<text
class=
"count"
>
转发
</text>
</button>
</view>
<view
v-show=
"item.userLike==1"
class=
"p-item"
@
click
.
stop=
"cancelCollection(item.id, index)"
>
<u-icon
name=
"thumb-up-fill"
size=
"24"
color=
"#cc0000"
></u-icon>
<text
class=
"count"
>
{{
item
.
likes
}}
</text>
</view>
<view
v-show=
"item.userLike==0"
class=
"p-item"
@
click
.
stop=
"addCollection(item.id, index)"
>
<u-icon
name=
"thumb-up"
size=
"24"
></u-icon>
<text
class=
"count"
>
{{
item
.
likes
>
0
?
item
.
likes
:
'点赞'
}}
</text>
</view>
</view>
</view>
</view>
</block>
</view>
</
template
>
<
script
>
import
common
from
'@/mixins/common'
;
const
app
=
getApp
();
export
default
{
name
:
'post-list'
,
mixins
:
[
common
],
props
:
{
list
:
Array
,
uid
:
Number
,
},
data
()
{
return
{
currentIndex
:
0
,
path
:
'/pages/loading'
,
};
},
computed
:
{
timestamp
()
{
return
Date
.
parse
(
new
Date
())
/
1000
;
}
},
methods
:
{
showShares
(
index
)
{
this
.
currentIndex
=
index
},
cancelCollection
(
id
,
index
)
{
this
.
post
({
url
:
'/comment/like'
,
data
:
{
commentId
:
id
,
type
:
0
,
session
:
app
.
globalData
.
token
,
},
showLoading
:
false
,
success
:
({
data
})
=>
{
this
.
list
[
index
].
userLike
=
0
if
(
this
.
list
[
index
].
likes
!=
0
)
{
this
.
list
[
index
].
likes
-=
1
}
}
})
},
addCollection
(
id
,
index
)
{
this
.
post
({
url
:
'/comment/like'
,
data
:
{
commentId
:
id
,
type
:
1
,
session
:
app
.
globalData
.
token
,
},
showLoading
:
false
,
success
:
({
data
})
=>
{
this
.
list
[
index
].
userLike
=
1
this
.
list
[
index
].
likes
+=
1
}
})
},
previewImage
(
url
,
urls
,
integral
,
post_id
)
{
let
that
=
this
;
uni
.
previewImage
({
current
:
url
,
// 当前显示图片的http链接
urls
:
urls
// 需要预览的图片http链接列表
});
},
previewMedia
(
url
,
userLike
,
likeCount
,
commentId
)
{
console
.
log
(
url
+
"--"
+
userLike
)
uni
.
navigateTo
({
url
:
'/pagesB/moments/video-detail?media='
+
url
+
"&userLike="
+
userLike
+
"&likes="
+
likeCount
+
"&commentId="
+
commentId
});
},
jump
(
val
)
{
},
}
};
</
script
>
<
style
lang=
"scss"
scoped
>
// 分享弹窗
.share-wrap
{
display
:
flex
;
padding
:
30rpx
;
width
:
50%
;
margin
:
0
auto
;
.share-item
{
display
:
flex
;
flex-direction
:
column
;
justify-content
:
center
;
align-items
:
center
;
&
:nth-child
(
1
)
{
margin-right
:
auto
;
}
image
{
width
:
100rpx
;
height
:
100rpx
;
}
text
{
font-size
:
24rpx
;
margin-top
:
20rpx
;
}
}
}
.post-item
{
border-radius
:
20rpx
;
background
:
#fff
;
padding
:
20rpx
;
margin
:
20rpx
;
.post-content
{
margin-top
:
20rpx
;
.img-style-1
{
display
:
block
;
width
:
100%
;
max-height
:
600rpx
;
border-radius
:
5px
;
overflow
:
hidden
;
}
.img-style-2
{
display
:
flex
;
image
{
margin
:
5rpx
;
border-radius
:
5px
;
width
:
100%
;
height
:
294rpx
;
}
}
.img-style-3
{
display
:
flex
;
flex-wrap
:
wrap
;
image
{
width
:
31
.3%
;
height
:
200rpx
;
margin
:
1%
;
border-radius
:
5px
;
}
}
}
.address
{
display
:
flex
;
font-size
:
20rpx
;
background-color
:
#f5f5f5
;
border-radius
:
20rpx
;
display
:
inline-block
;
padding
:
5rpx
20rpx
;
margin
:
20rpx
0
;
.icon
{
margin-right
:
5rpx
;
}
}
}
.post-item-top-user
{
display
:
flex
;
align-items
:
center
;
.avatar
{
width
:
85rpx
;
height
:
85rpx
;
border-radius
:
50%
;
margin-right
:
20rpx
;
}
.center
{
flex
:
1
;
margin-left
:
10rpx
;
display
:
flex
;
flex-direction
:
column
;
font-size
:
24rpx
;
color
:
#999
;
.username
{
font-size
:
32rpx
;
font-weight
:
600
;
color
:
#616161
;
}
.official
{
display
:
inline-block
;
font-size
:
20rpx
;
color
:
#fff
;
background-color
:
$themes-color
;
padding
:
5rpx
10rpx
;
border-radius
:
10rpx
;
margin-right
:
10rpx
;
}
.time
{
float
:
left
;
}
}
.right
{
height
:
85rpx
;
.arrow-down
{
color
:
#999
;
}
}
}
.post-text
{
font-size
:
30rpx
;
margin-bottom
:
10rpx
;
display
:
block
;
display
:
-
webkit-box
;
-webkit-box-orient
:
vertical
;
-webkit-line-clamp
:
5
;
white-space
:
pre-wrap
;
overflow
:
hidden
;
}
.p-footer
{
display
:
flex
;
margin-top
:
20rpx
;
// margin: 20rpx 0;
.p-item
{
width
:
200rpx
;
margin
:
0
auto
;
color
:
#616161
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
.count
{
margin-left
:
10rpx
;
font-size
:
32rpx
;
}
}
.p-item
[
hidden
]
{
display
:
none
!
important
;
}
}
.video-wrap
{
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
position
:
relative
;
width
:
100%
;
height
:
500rpx
;
.icon
{
width
:
100rpx
;
height
:
100rpx
;
z-index
:
999
;
}
image
{
position
:
absolute
;
}
}
.u-reset-button
{
display
:
flex
;
padding
:
0
;
background-color
:
transparent
;
font-size
:
inherit
;
line-height
:
inherit
;
color
:
inherit
;
justify-content
:
center
;
}
</
style
>
vedio/components/q-button/q-button.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view>
<button
class=
"reset-button button"
@
click=
"onClick"
hover-class=
"button-hover"
:class=
"[shape == 'circle' ? 'round-circle' : '']"
>
<slot></slot>
</button>
</view>
</
template
>
<
script
>
/**
* m-field button 按钮组件
* @description 常用按钮组件。
* @tutorial https://ui.ymeoo.cn
* @property {String} color 按钮主题色
* @property {String} shape 设置为circle,则按钮两边为半圆形
* @event {Function} click 组件自定义点击事件
* @example <u-form-item label="姓名"><u-input v-model="form.name" /></u-form-item>
*/
export
default
{
name
:
'q-button'
,
props
:
{
shape
:
{
type
:
String
,
default
:
'circle'
}
},
data
()
{
return
{};
},
methods
:
{
onClick
()
{
this
.
$emit
(
'click'
,
''
);
}
}
};
</
script
>
<
style
lang=
"scss"
scoped
>
// 去除button的所有默认样式
.reset-button
{
padding
:
0
;
font-size
:
inherit
;
line-height
:
inherit
;
background-color
:
transparent
;
color
:
inherit
;
}
.
reset-button
:
:
after
{
border
:
none
;
}
// button样式
.button
{
display
:
block
;
padding
:
20rpx
;
margin
:
20rpx
;
background-image
:
-moz-linear-gradient
(
135deg
,
rgb
(
0
,
255
,
255
)
,
rgb
(
29
,
147
,
251
));
background-image
:
-webkit-linear-gradient
(
135deg
,
rgb
(
0
,
255
,
255
)
,
rgb
(
29
,
147
,
251
));
background-image
:
linear-gradient
(
135deg
,
rgb
(
0
,
255
,
255
)
,
rgb
(
29
,
147
,
251
));
color
:
#fff
;
}
.button-hover
{
background-color
:
#f5f5f5
!
important
;
}
.round-circle
{
border-radius
:
100rpx
;
}
</
style
>
vedio/components/send-code/send-code.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<button
:disabled=
"runSecond > 0"
:class=
"runSecond > 0 ? 'disabled' : ''"
class=
"send-code"
@
click=
"handleClick"
>
{{
tmpStr
}}
</button>
</
template
>
<
script
>
import
{
message
}
from
'@/utils/fun'
;
import
{
isPhoneNumber
}
from
'@/utils/validate.js'
;
export
default
{
name
:
'send-code'
,
props
:
{
value
:
String
,
code
:
String
,
initStr
:
{
type
:
String
,
default
:
'获取验证码'
},
second
:
{
type
:
Number
,
default
:
60
},
runStr
:
{
type
:
String
,
default
:
'{%s}秒后重新获取'
},
resetStr
:
{
type
:
String
,
default
:
'重新获取验证码'
}
},
data
()
{
return
{
tmpStr
:
this
.
initStr
,
runSecond
:
0
,
timer
:
null
};
},
mounted
()
{
uni
.
getStorage
({
key
:
'send-code-time'
,
success
:
data
=>
{
const
lastSecond
=
~~
((
data
-
new
Date
().
getTime
())
/
1000
);
if
(
lastSecond
>
0
)
{
this
.
runSecond
=
lastSecond
;
this
.
run
();
}
}
});
},
beforeDestroy
()
{
if
(
this
.
timer
)
{
clearInterval
(
this
.
timer
);
}
},
methods
:
{
handleClick
()
{
if
(
!
isPhoneNumber
(
this
.
value
))
{
message
.
notify
(
'请输入正确手机号'
);
return
;
}
if
(
!
this
.
code
)
{
message
.
notify
(
'请输入图形验证码'
);
return
;
}
this
.
run
();
},
run
()
{
if
(
!
this
.
runSecond
)
{
this
.
runSecond
=
this
.
second
;
this
.
$emit
(
'send'
);
uni
.
setStorage
({
key
:
'send-code-time'
,
data
:
new
Date
().
getTime
()
+
this
.
second
*
1000
});
}
this
.
tmpStr
=
this
.
getStr
();
this
.
timer
=
setInterval
(()
=>
{
this
.
runSecond
=
--
this
.
runSecond
;
this
.
tmpStr
=
this
.
getStr
();
if
(
this
.
runSecond
<=
0
)
{
this
.
timeout
();
}
},
1000
);
},
timeout
()
{
this
.
tmpStr
=
this
.
resetStr
;
this
.
runSecond
=
0
;
uni
.
removeStorage
({
key
:
'send-code-time'
});
clearInterval
(
this
.
timer
);
},
getStr
()
{
return
this
.
runStr
.
replace
(
/
\{([^
{
]
*
?)
%s
(
.*
?)\}
/g
,
this
.
runSecond
);
}
}
};
</
script
>
<
style
lang=
"scss"
>
@import
'@/scss/uni.scss'
;
.send-code
{
line-height
:
1
;
padding
:
18rpx
38rpx
;
background-color
:
#c6c6c6
;
color
:
$bg-color
;
border
:
none
;
font-size
:
24rpx
;
width
:
auto
!
important
;
// margin: 0 !important;
font-weight
:
normal
;
border-radius
:
70rpx
;
&
:
:
after
{
content
:
none
;
}
&
.disabled
{
background-color
:
darken
(
$color
:
#c6c6c6
,
$amount
:
15%
)
!
important
;
color
:
$bg-color
!
important
;
}
}
</
style
>
vedio/components/service-img-dialog/service-img-dialog.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<u-popup
customStyle=
"background-color:#00000000;"
:show=
"showDialog"
mode=
"center"
round=
"20rpx"
:closeOnClickOverlay=
"true"
@
close=
"close"
>
<view
class=
"container"
>
<view
class=
"img-wrap"
>
<u-text
align=
"center"
text=
"长按识别二维码"
color=
"#63656D"
size=
"18"
></u-text>
<u-text
align=
"center"
text=
"添加客服"
color=
"#B6B8BA"
size=
"18"
></u-text>
<image
class=
"mt-20"
:show-menu-by-longpress=
"true"
:src=
"serviceUrl"
></image>
</view>
<u-icon
name=
"close-circle"
color=
"#fff"
size=
"30"
@
click=
"close"
></u-icon>
</view>
</u-popup>
</
template
>
<
script
>
import
{
message
}
from
'@/utils/fun'
;
export
default
{
name
:
"service-img-dialog"
,
props
:
{
url
:
String
,
show
:
{
type
:
Boolean
,
default
:
false
},
},
data
()
{
return
{
showDialog
:
this
.
show
,
serviceUrl
:
this
.
url
};
},
watch
:
{
show
:
{
handler
:
function
(
newVal
,
oldVal
)
{
this
.
showDialog
=
newVal
;
}
},
url
:
{
handler
:
function
(
newVal
,
oldVal
)
{
this
.
serviceUrl
=
newVal
}
}
},
methods
:
{
close
()
{
this
.
showDialog
=
false
this
.
$emit
(
'dismiss'
);
}
},
}
</
script
>
<
style
lang=
"scss"
>
.container
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
.img-wrap
{
margin-top
:
100rpx
;
border-radius
:
10rpx
;
padding
:
20rpx
;
width
:
500rpx
;
background-color
:
#FAFBFE
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
margin-bottom
:
20rpx
;
}
image
{
width
:
400rpx
;
height
:
400rpx
;
}
}
</
style
>
vedio/components/time-down/time-down.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view
class=
"time-down"
>
{{
text
}}
</view>
</
template
>
<
script
>
export
default
{
name
:
'time-down'
,
props
:
{
time
:
String
},
data
()
{
return
{
text
:
'00:00:00'
,
timespan
:
0
,
timer
:
undefined
};
},
// watch: {
// value: {
// immediate: true,
// handler() {
// this.create();
// }
// }
// },
created
()
{
this
.
timespan
=
new
Date
(
this
.
time
).
getTime
()
-
new
Date
().
getTime
();
this
.
countdown
();
},
beforeDestroy
()
{
clearInterval
(
this
.
timer
);
},
methods
:
{
countdown
()
{
if
(
this
.
timespan
<
0
)
{
this
.
text
=
'已上架'
}
else
{
this
.
timer
=
setInterval
(()
=>
{
let
{
timespan
}
=
this
;
this
.
timespan
-=
1000
;
if
(
this
.
timespan
<=
0
)
{
this
.
text
=
'已上架'
}
else
{
let
leftd
=
Math
.
floor
(
timespan
/
(
1000
*
60
*
60
*
24
)),
//计算天数
lefth
=
(
'00'
+
Math
.
floor
((
timespan
/
(
1000
*
60
*
60
))
%
24
)).
slice
(
-
2
),
//计算小时数
leftm
=
(
'00'
+
Math
.
floor
((
timespan
/
(
1000
*
60
))
%
60
)).
slice
(
-
2
),
//计算分钟数
lefts
=
(
'00'
+
Math
.
floor
((
timespan
/
1000
)
%
60
)).
slice
(
-
2
);
//计算秒数
this
.
text
=
"即将开售"
+
(
leftd
>
0
?
leftd
+
'天'
:
''
)
+
lefth
+
':'
+
leftm
+
':'
+
lefts
;
//返回倒计时的字符串
}
},
1000
);
}
}
}
};
</
script
>
<
style
lang=
"scss"
>
@import
'@/scss/uni.scss'
;
.time-down
{
display
:
inline-block
;
margin-left
:
10rpx
;
}
</
style
>
vedio/components/uni-file-picker/choose-and-upload-file.js
deleted
100644 → 0
View file @
abb53a01
'use strict'
;
const
ERR_MSG_OK
=
'chooseAndUploadFile:ok'
;
const
ERR_MSG_FAIL
=
'chooseAndUploadFile:fail'
;
function
chooseImage
(
opts
)
{
const
{
count
,
sizeType
=
[
'original'
,
'compressed'
],
sourceType
=
[
'album'
,
'camera'
],
extension
}
=
opts
return
new
Promise
((
resolve
,
reject
)
=>
{
uni
.
chooseImage
({
count
,
sizeType
,
sourceType
,
extension
,
success
(
res
)
{
resolve
(
normalizeChooseAndUploadFileRes
(
res
,
'image'
));
},
fail
(
res
)
{
reject
({
errMsg
:
res
.
errMsg
.
replace
(
'chooseImage:fail'
,
ERR_MSG_FAIL
),
});
},
});
});
}
function
chooseVideo
(
opts
)
{
const
{
camera
,
compressed
,
maxDuration
,
sourceType
=
[
'album'
,
'camera'
],
extension
}
=
opts
;
return
new
Promise
((
resolve
,
reject
)
=>
{
uni
.
chooseVideo
({
camera
,
compressed
,
maxDuration
,
sourceType
,
extension
,
success
(
res
)
{
const
{
tempFilePath
,
duration
,
size
,
height
,
width
}
=
res
;
resolve
(
normalizeChooseAndUploadFileRes
({
errMsg
:
'chooseVideo:ok'
,
tempFilePaths
:
[
tempFilePath
],
tempFiles
:
[
{
name
:
(
res
.
tempFile
&&
res
.
tempFile
.
name
)
||
''
,
path
:
tempFilePath
,
size
,
type
:
(
res
.
tempFile
&&
res
.
tempFile
.
type
)
||
''
,
width
,
height
,
duration
,
fileType
:
'video'
,
cloudPath
:
''
,
},
],
},
'video'
));
},
fail
(
res
)
{
reject
({
errMsg
:
res
.
errMsg
.
replace
(
'chooseVideo:fail'
,
ERR_MSG_FAIL
),
});
},
});
});
}
function
chooseAll
(
opts
)
{
const
{
count
,
extension
}
=
opts
;
return
new
Promise
((
resolve
,
reject
)
=>
{
let
chooseFile
=
uni
.
chooseFile
;
if
(
typeof
wx
!==
'undefined'
&&
typeof
wx
.
chooseMessageFile
===
'function'
)
{
chooseFile
=
wx
.
chooseMessageFile
;
}
if
(
typeof
chooseFile
!==
'function'
)
{
return
reject
({
errMsg
:
ERR_MSG_FAIL
+
' 请指定 type 类型,该平台仅支持选择 image 或 video。'
,
});
}
chooseFile
({
type
:
'all'
,
count
,
extension
,
success
(
res
)
{
resolve
(
normalizeChooseAndUploadFileRes
(
res
));
},
fail
(
res
)
{
reject
({
errMsg
:
res
.
errMsg
.
replace
(
'chooseFile:fail'
,
ERR_MSG_FAIL
),
});
},
});
});
}
function
normalizeChooseAndUploadFileRes
(
res
,
fileType
)
{
res
.
tempFiles
.
forEach
((
item
,
index
)
=>
{
if
(
!
item
.
name
)
{
item
.
name
=
item
.
path
.
substring
(
item
.
path
.
lastIndexOf
(
'/'
)
+
1
);
}
if
(
fileType
)
{
item
.
fileType
=
fileType
;
}
item
.
cloudPath
=
Date
.
now
()
+
'_'
+
index
+
item
.
name
.
substring
(
item
.
name
.
lastIndexOf
(
'.'
));
});
if
(
!
res
.
tempFilePaths
)
{
res
.
tempFilePaths
=
res
.
tempFiles
.
map
((
file
)
=>
file
.
path
);
}
return
res
;
}
function
uploadCloudFiles
(
files
,
max
=
5
,
onUploadProgress
)
{
files
=
JSON
.
parse
(
JSON
.
stringify
(
files
))
const
len
=
files
.
length
let
count
=
0
let
self
=
this
return
new
Promise
(
resolve
=>
{
while
(
count
<
max
)
{
next
()
}
function
next
()
{
let
cur
=
count
++
if
(
cur
>=
len
)
{
!
files
.
find
(
item
=>
!
item
.
url
&&
!
item
.
errMsg
)
&&
resolve
(
files
)
return
}
const
fileItem
=
files
[
cur
]
const
index
=
self
.
files
.
findIndex
(
v
=>
v
.
uuid
===
fileItem
.
uuid
)
fileItem
.
url
=
''
delete
fileItem
.
errMsg
uniCloud
.
uploadFile
({
filePath
:
fileItem
.
path
,
cloudPath
:
fileItem
.
cloudPath
,
fileType
:
fileItem
.
fileType
,
onUploadProgress
:
res
=>
{
res
.
index
=
index
onUploadProgress
&&
onUploadProgress
(
res
)
}
})
.
then
(
res
=>
{
fileItem
.
url
=
res
.
fileID
fileItem
.
index
=
index
if
(
cur
<
len
)
{
next
()
}
})
.
catch
(
res
=>
{
fileItem
.
errMsg
=
res
.
errMsg
||
res
.
message
fileItem
.
index
=
index
if
(
cur
<
len
)
{
next
()
}
})
}
})
}
function
uploadFiles
(
choosePromise
,
{
onChooseFile
,
onUploadProgress
})
{
return
choosePromise
.
then
((
res
)
=>
{
if
(
onChooseFile
)
{
const
customChooseRes
=
onChooseFile
(
res
);
if
(
typeof
customChooseRes
!==
'undefined'
)
{
return
Promise
.
resolve
(
customChooseRes
).
then
((
chooseRes
)
=>
typeof
chooseRes
===
'undefined'
?
res
:
chooseRes
);
}
}
return
res
;
})
.
then
((
res
)
=>
{
if
(
res
===
false
)
{
return
{
errMsg
:
ERR_MSG_OK
,
tempFilePaths
:
[],
tempFiles
:
[],
};
}
return
res
})
}
function
chooseAndUploadFile
(
opts
=
{
type
:
'all'
})
{
if
(
opts
.
type
===
'image'
)
{
return
uploadFiles
(
chooseImage
(
opts
),
opts
);
}
else
if
(
opts
.
type
===
'video'
)
{
return
uploadFiles
(
chooseVideo
(
opts
),
opts
);
}
return
uploadFiles
(
chooseAll
(
opts
),
opts
);
}
export
{
chooseAndUploadFile
,
uploadCloudFiles
};
vedio/components/uni-file-picker/uni-file-picker.vue
deleted
100644 → 0
View file @
abb53a01
This diff is collapsed.
Click to expand it.
vedio/components/uni-file-picker/upload-file.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view
class=
"uni-file-picker__files"
>
<view
v-if=
"!readonly"
class=
"files-button"
@
click=
"choose"
>
<slot></slot>
</view>
<!-- :class="
{'is-text-box':showType === 'list'}" -->
<view
v-if=
"list.length > 0"
class=
"uni-file-picker__lists is-text-box"
:style=
"borderStyle"
>
<!-- ,'is-list-card':showType === 'list-card' -->
<view
class=
"uni-file-picker__lists-box"
v-for=
"(item ,index) in list"
:key=
"index"
:class=
"
{
'files-border':index !== 0
&&
styles.dividline}"
:style="index !== 0
&&
styles.dividline
&&
borderLineStyle">
<view
class=
"uni-file-picker__item"
>
<!-- :class="
{'is-text-image':showType === 'list'}" -->
<!--
<view
class=
"files__image is-text-image"
>
<image
class=
"header-image"
:src=
"item.logo"
mode=
"aspectFit"
></image>
</view>
-->
<view
class=
"files__name"
>
<video
:src=
"item.url"
></video>
</view>
<view
v-if=
"delIcon&&!readonly"
class=
"icon-del-box icon-files"
@
click=
"delFile(index)"
>
<view
class=
"icon-del icon-files"
></view>
<view
class=
"icon-del rotate"
></view>
</view>
</view>
<view
v-if=
"(item.progress && item.progress !== 100) ||item.progress===0 "
class=
"file-picker__progress"
>
<progress
class=
"file-picker__progress-item"
:percent=
"item.progress === -1?0:item.progress"
stroke-width=
"4"
:backgroundColor=
"item.errMsg?'#ff5a5f':'#EBEBEB'"
/>
</view>
<view
v-if=
"item.status === 'error'"
class=
"file-picker__mask"
@
click
.
stop=
"uploadFiles(item,index)"
>
点击重试
</view>
</view>
</view>
</view>
</
template
>
<
script
>
export
default
{
name
:
"uploadFile"
,
emits
:[
'uploadFiles'
,
'choose'
,
'delFile'
],
props
:
{
filesList
:
{
type
:
Array
,
default
()
{
return
[]
}
},
delIcon
:
{
type
:
Boolean
,
default
:
true
},
limit
:
{
type
:
[
Number
,
String
],
default
:
9
},
showType
:
{
type
:
String
,
default
:
''
},
listStyles
:
{
type
:
Object
,
default
()
{
return
{
// 是否显示边框
border
:
true
,
// 是否显示分隔线
dividline
:
true
,
// 线条样式
borderStyle
:
{}
}
}
},
readonly
:{
type
:
Boolean
,
default
:
false
}
},
computed
:
{
list
()
{
let
files
=
[]
this
.
filesList
.
forEach
(
v
=>
{
files
.
push
(
v
)
})
return
files
},
styles
()
{
let
styles
=
{
border
:
true
,
dividline
:
true
,
'border-style'
:
{}
}
return
Object
.
assign
(
styles
,
this
.
listStyles
)
},
borderStyle
()
{
let
{
borderStyle
,
border
}
=
this
.
styles
let
obj
=
{}
if
(
!
border
)
{
obj
.
border
=
'none'
}
else
{
let
width
=
(
borderStyle
&&
borderStyle
.
width
)
||
1
width
=
this
.
value2px
(
width
)
let
radius
=
(
borderStyle
&&
borderStyle
.
radius
)
||
5
radius
=
this
.
value2px
(
radius
)
obj
=
{
'border-width'
:
width
,
'border-style'
:
(
borderStyle
&&
borderStyle
.
style
)
||
'solid'
,
'border-color'
:
(
borderStyle
&&
borderStyle
.
color
)
||
'#eee'
,
'border-radius'
:
radius
}
}
let
classles
=
''
for
(
let
i
in
obj
)
{
classles
+=
`
${
i
}
:
${
obj
[
i
]}
;`
}
return
classles
},
borderLineStyle
()
{
let
obj
=
{}
let
{
borderStyle
}
=
this
.
styles
if
(
borderStyle
&&
borderStyle
.
color
)
{
obj
[
'border-color'
]
=
borderStyle
.
color
}
if
(
borderStyle
&&
borderStyle
.
width
)
{
let
width
=
borderStyle
&&
borderStyle
.
width
||
1
let
style
=
borderStyle
&&
borderStyle
.
style
||
0
if
(
typeof
width
===
'number'
)
{
width
+=
'px'
}
else
{
width
=
width
.
indexOf
(
'px'
)
?
width
:
width
+
'px'
}
obj
[
'border-width'
]
=
width
if
(
typeof
style
===
'number'
)
{
style
+=
'px'
}
else
{
style
=
style
.
indexOf
(
'px'
)
?
style
:
style
+
'px'
}
obj
[
'border-top-style'
]
=
style
}
let
classles
=
''
for
(
let
i
in
obj
)
{
classles
+=
`
${
i
}
:
${
obj
[
i
]}
;`
}
return
classles
}
},
methods
:
{
uploadFiles
(
item
,
index
)
{
this
.
$emit
(
"uploadFiles"
,
{
item
,
index
})
},
choose
()
{
this
.
$emit
(
"choose"
)
},
delFile
(
index
)
{
this
.
$emit
(
'delFile'
,
index
)
},
value2px
(
value
)
{
if
(
typeof
value
===
'number'
)
{
value
+=
'px'
}
else
{
value
=
value
.
indexOf
(
'px'
)
!==
-
1
?
value
:
value
+
'px'
}
return
value
}
}
}
</
script
>
<
style
lang=
"scss"
>
.uni-file-picker__files
{
/* #ifndef APP-NVUE */
display
:
flex
;
/* #endif */
flex-direction
:
column
;
justify-content
:
flex-start
;
}
.files-button
{
// border: 1px red solid;
}
.uni-file-picker__lists
{
position
:
relative
;
margin-top
:
5px
;
overflow
:
hidden
;
}
.file-picker__mask
{
/* #ifndef APP-NVUE */
display
:
flex
;
/* #endif */
justify-content
:
center
;
align-items
:
center
;
position
:
absolute
;
right
:
0
;
top
:
0
;
bottom
:
0
;
left
:
0
;
color
:
#fff
;
font-size
:
14px
;
background-color
:
rgba
(
0
,
0
,
0
,
0
.4
);
}
.uni-file-picker__lists-box
{
position
:
relative
;
}
.uni-file-picker__item
{
/* #ifndef APP-NVUE */
display
:
flex
;
/* #endif */
align-items
:
center
;
padding
:
8px
10px
;
padding-right
:
5px
;
padding-left
:
10px
;
}
.files-border
{
border-top
:
1px
#eee
solid
;
}
.files__name
{
flex
:
1
;
font-size
:
14px
;
color
:
#666
;
margin-right
:
25px
;
/* #ifndef APP-NVUE */
word-break
:
break-all
;
word-wrap
:
break-word
;
/* #endif */
}
.icon-files
{
/* #ifndef APP-NVUE */
position
:
static
;
background-color
:
initial
;
/* #endif */
}
// .icon-files .icon-del {
// background-color: #333;
// width: 12px;
// height: 1px;
// }
.is-list-card
{
border
:
1px
#eee
solid
;
margin-bottom
:
5px
;
border-radius
:
5px
;
box-shadow
:
0
0
2px
0px
rgba
(
0
,
0
,
0
,
0
.1
);
padding
:
5px
;
}
.files__image
{
width
:
40px
;
height
:
40px
;
margin-right
:
10px
;
}
.header-image
{
width
:
100%
;
height
:
100%
;
}
.is-text-box
{
border
:
1px
#eee
solid
;
border-radius
:
5px
;
}
.is-text-image
{
width
:
25px
;
height
:
25px
;
margin-left
:
5px
;
}
.rotate
{
position
:
absolute
;
transform
:
rotate
(
90deg
);
}
.icon-del-box
{
/* #ifndef APP-NVUE */
display
:
flex
;
margin
:
auto
0
;
/* #endif */
align-items
:
center
;
justify-content
:
center
;
position
:
absolute
;
top
:
0px
;
bottom
:
0
;
right
:
5px
;
height
:
26px
;
width
:
26px
;
// border-radius: 50%;
// background-color: rgba(0, 0, 0, 0.5);
z-index
:
2
;
transform
:
rotate
(
-45deg
);
}
.icon-del
{
width
:
15px
;
height
:
1px
;
background-color
:
#333
;
// border-radius: 1px;
}
/* #ifdef H5 */
@media
all
and
(
min-width
:
768px
)
{
.uni-file-picker__files
{
max-width
:
375px
;
}
}
/* #endif */
</
style
>
vedio/components/uni-file-picker/upload-image.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view
class=
"uni-file-picker__container"
>
<view
class=
"file-picker__box"
v-for=
"(item,index) in filesList"
:key=
"index"
:style=
"boxStyle"
>
<view
class=
"file-picker__box-content"
:style=
"borderStyle"
>
<image
class=
"file-image"
:src=
"item.url"
mode=
"aspectFill"
@
click
.
stop=
"prviewImage(item,index)"
></image>
<view
v-if=
"delIcon && !readonly"
class=
"icon-del-box"
@
click
.
stop=
"delFile(index)"
>
<view
class=
"icon-del"
></view>
<view
class=
"icon-del rotate"
></view>
</view>
<view
v-if=
"(item.progress && item.progress !== 100) ||item.progress===0 "
class=
"file-picker__progress"
>
<progress
class=
"file-picker__progress-item"
:percent=
"item.progress === -1?0:item.progress"
stroke-width=
"4"
:backgroundColor=
"item.errMsg?'#ff5a5f':'#EBEBEB'"
/>
</view>
<view
v-if=
"item.errMsg"
class=
"file-picker__mask"
@
click
.
stop=
"uploadFiles(item,index)"
>
点击重试
</view>
</view>
</view>
<view
v-if=
"filesList.length
<
limit
&&
!
readonly
"
class=
"file-picker__box"
:style=
"boxStyle"
>
<view
class=
"file-picker__box-content is-add"
:style=
"borderStyle"
@
click=
"choose"
>
<slot>
<view
class=
"icon-add"
></view>
<view
class=
"icon-add rotate"
></view>
</slot>
</view>
</view>
</view>
</
template
>
<
script
>
export
default
{
name
:
"uploadImage"
,
emits
:[
'uploadFiles'
,
'choose'
,
'delFile'
],
props
:
{
filesList
:
{
type
:
Array
,
default
()
{
return
[]
}
},
disabled
:{
type
:
Boolean
,
default
:
false
},
disablePreview
:
{
type
:
Boolean
,
default
:
false
},
limit
:
{
type
:
[
Number
,
String
],
default
:
9
},
imageStyles
:
{
type
:
Object
,
default
()
{
return
{
width
:
'auto'
,
height
:
'auto'
,
border
:
{}
}
}
},
delIcon
:
{
type
:
Boolean
,
default
:
true
},
readonly
:{
type
:
Boolean
,
default
:
false
}
},
computed
:
{
styles
()
{
let
styles
=
{
width
:
'auto'
,
height
:
'auto'
,
border
:
{}
}
return
Object
.
assign
(
styles
,
this
.
imageStyles
)
},
boxStyle
()
{
const
{
width
=
'auto'
,
height
=
'auto'
}
=
this
.
styles
let
obj
=
{}
if
(
height
===
'auto'
)
{
if
(
width
!==
'auto'
)
{
obj
.
height
=
this
.
value2px
(
width
)
obj
[
'padding-top'
]
=
0
}
else
{
obj
.
height
=
0
}
}
else
{
obj
.
height
=
this
.
value2px
(
height
)
obj
[
'padding-top'
]
=
0
}
if
(
width
===
'auto'
)
{
if
(
height
!==
'auto'
)
{
obj
.
width
=
this
.
value2px
(
height
)
}
else
{
obj
.
width
=
'33.3%'
}
}
else
{
obj
.
width
=
this
.
value2px
(
width
)
}
let
classles
=
''
for
(
let
i
in
obj
){
classles
+=
`
${
i
}
:
${
obj
[
i
]}
;`
}
return
classles
},
borderStyle
()
{
let
{
border
}
=
this
.
styles
let
obj
=
{}
if
(
typeof
border
===
'boolean'
)
{
obj
.
border
=
border
?
'1px #eee solid'
:
'none'
}
else
{
let
width
=
(
border
&&
border
.
width
)
||
1
width
=
this
.
value2px
(
width
)
let
radius
=
(
border
&&
border
.
radius
)
||
5
radius
=
this
.
value2px
(
radius
)
obj
=
{
}
}
let
classles
=
''
for
(
let
i
in
obj
){
classles
+=
`
${
i
}
:
${
obj
[
i
]}
;`
}
return
classles
}
},
methods
:
{
uploadFiles
(
item
,
index
)
{
this
.
$emit
(
"uploadFiles"
,
item
)
},
choose
()
{
this
.
$emit
(
"choose"
)
},
delFile
(
index
)
{
this
.
$emit
(
'delFile'
,
index
)
},
prviewImage
(
img
,
index
)
{
let
urls
=
[]
if
(
Number
(
this
.
limit
)
===
1
&&
this
.
disablePreview
&&!
this
.
disabled
){
this
.
$emit
(
"choose"
)
}
if
(
this
.
disablePreview
)
return
this
.
filesList
.
forEach
(
i
=>
{
urls
.
push
(
i
.
url
)
})
uni
.
previewImage
({
urls
:
urls
,
current
:
index
});
},
value2px
(
value
)
{
if
(
typeof
value
===
'number'
)
{
value
+=
'px'
}
else
{
if
(
value
.
indexOf
(
'%'
)
===
-
1
)
{
value
=
value
.
indexOf
(
'px'
)
!==
-
1
?
value
:
value
+
'px'
}
}
return
value
}
}
}
</
script
>
<
style
lang=
"scss"
>
.uni-file-picker__container
{
/* #ifndef APP-NVUE */
display
:
flex
;
box-sizing
:
border-box
;
/* #endif */
flex-wrap
:
wrap
;
margin
:
-5px
;
}
.file-picker__box
{
position
:
relative
;
// flex: 0 0 33.3%;
width
:
33
.3%
;
height
:
0
;
padding-top
:
33
.33%
;
/* #ifndef APP-NVUE */
box-sizing
:
border-box
;
/* #endif */
}
.file-picker__box-content
{
position
:
absolute
;
top
:
0
;
right
:
0
;
bottom
:
0
;
left
:
0
;
margin
:
5px
;
border-radius
:
8px
;
overflow
:
hidden
;
}
.file-picker__progress
{
position
:
absolute
;
bottom
:
0
;
left
:
0
;
right
:
0
;
/* border: 1px red solid; */
z-index
:
2
;
}
.file-picker__progress-item
{
width
:
100%
;
}
.file-picker__mask
{
/* #ifndef APP-NVUE */
display
:
flex
;
/* #endif */
justify-content
:
center
;
align-items
:
center
;
position
:
absolute
;
right
:
0
;
top
:
0
;
bottom
:
0
;
left
:
0
;
color
:
#fff
;
font-size
:
12px
;
background-color
:
rgba
(
0
,
0
,
0
,
0
.4
);
}
.file-image
{
width
:
100%
;
height
:
100%
;
}
.is-add
{
/* #ifndef APP-NVUE */
display
:
flex
;
/* #endif */
align-items
:
center
;
justify-content
:
center
;
}
.icon-add
{
width
:
50px
;
height
:
5px
;
background-color
:
#f1f1f1
;
border-radius
:
2px
;
}
.rotate
{
position
:
absolute
;
transform
:
rotate
(
90deg
);
}
.icon-del-box
{
/* #ifndef APP-NVUE */
display
:
flex
;
/* #endif */
align-items
:
center
;
justify-content
:
center
;
position
:
absolute
;
top
:
5px
;
right
:
5px
;
height
:
26px
;
width
:
26px
;
border-radius
:
50%
;
background-color
:
rgba
(
0
,
0
,
0
,
0
.5
);
z-index
:
2
;
transform
:
rotate
(
-45deg
);
}
.icon-del
{
width
:
15px
;
height
:
2px
;
background-color
:
#fff
;
border-radius
:
2px
;
}
</
style
>
vedio/components/uni-file-picker/utils.js
deleted
100644 → 0
View file @
abb53a01
/**
* 获取文件名和后缀
* @param {String} name
*/
export
const
get_file_ext
=
(
name
)
=>
{
const
last_len
=
name
.
lastIndexOf
(
'.'
)
const
len
=
name
.
length
return
{
name
:
name
.
substring
(
0
,
last_len
),
ext
:
name
.
substring
(
last_len
+
1
,
len
)
}
}
/**
* 获取扩展名
* @param {Array} fileExtname
*/
export
const
get_extname
=
(
fileExtname
)
=>
{
if
(
!
Array
.
isArray
(
fileExtname
))
{
let
extname
=
fileExtname
.
replace
(
/
(\[
|
\])
/g
,
''
)
return
extname
.
split
(
','
)
}
else
{
return
fileExtname
}
return
[]
}
/**
* 获取文件和检测是否可选
*/
export
const
get_files_and_is_max
=
(
res
,
_extname
)
=>
{
let
filePaths
=
[]
let
files
=
[]
if
(
!
_extname
||
_extname
.
length
===
0
){
return
{
filePaths
,
files
}
}
res
.
tempFiles
.
forEach
(
v
=>
{
let
fileFullName
=
get_file_ext
(
v
.
name
)
const
extname
=
fileFullName
.
ext
.
toLowerCase
()
if
(
_extname
.
indexOf
(
extname
)
!==
-
1
)
{
files
.
push
(
v
)
filePaths
.
push
(
v
.
path
)
}
})
if
(
files
.
length
!==
res
.
tempFiles
.
length
)
{
uni
.
showToast
({
title
:
`当前选择了
${
res
.
tempFiles
.
length
}
个文件 ,
${
res
.
tempFiles
.
length
-
files
.
length
}
个文件格式不正确`
,
icon
:
'none'
,
duration
:
5000
})
}
return
{
filePaths
,
files
}
}
/**
* 获取图片信息
* @param {Object} filepath
*/
export
const
get_file_info
=
(
filepath
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
uni
.
getImageInfo
({
src
:
filepath
,
success
(
res
)
{
resolve
(
res
)
},
fail
(
err
)
{
reject
(
err
)
}
})
})
}
/**
* 获取封装数据
*/
export
const
get_file_data
=
async
(
files
,
type
=
'image'
)
=>
{
// 最终需要上传数据库的数据
let
fileFullName
=
get_file_ext
(
files
.
name
)
const
extname
=
fileFullName
.
ext
.
toLowerCase
()
let
filedata
=
{
name
:
files
.
name
,
uuid
:
files
.
uuid
,
extname
:
extname
||
''
,
cloudPath
:
files
.
cloudPath
,
fileType
:
files
.
fileType
,
url
:
files
.
path
||
files
.
path
,
size
:
files
.
size
,
//单位是字节
image
:
{},
path
:
files
.
path
,
video
:
{}
}
if
(
type
===
'image'
)
{
const
imageinfo
=
await
get_file_info
(
files
.
path
)
delete
filedata
.
video
filedata
.
image
.
width
=
imageinfo
.
width
filedata
.
image
.
height
=
imageinfo
.
height
filedata
.
image
.
location
=
imageinfo
.
path
}
else
{
delete
filedata
.
image
}
return
filedata
}
vedio/components/verify-code/verify-code.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view
class=
"verify-code"
>
<!-- 输入框 -->
<input
:value=
"code"
class=
"verify-code-input"
:focus=
"isFocus"
:password=
"isPassword"
:type=
"inputType"
:maxlength=
"itemSize"
@
input=
"input"
@
focus=
"inputFocus"
@
blur=
"inputBlur"
/>
<!-- 光标 -->
<view
v-if=
"cursorVisible && type !== 'middle'"
class=
"verify-code-cursor"
:style=
"
{ left: codeCursorLeft[code.length] + 'px', height: cursorHeight + 'px', backgroundColor: cursorColor }"
>
</view>
<!-- 输入框 - 组 -->
<view
class=
"verify-code-ground"
>
<template
v-for=
"(item, index) in itemSize"
>
<view
:key=
"index"
:style=
"
{ borderColor: code.length === index
&&
cursorVisible ? boxActiveColor : boxNormalColor }"
:class="['verify-code-box', `verify-code-box-${type + ''}`, `verify-code-box::after`]"
>
<view
:style=
"
{ borderColor: boxActiveColor }" class="verify-code-line" v-if="type === 'middle'
&&
!code[index]">
</view>
<text
class=
"verify-code-text"
>
{{
code
[
index
]
|
codeFormat
(
isPassword
)
}}
</text>
</view>
</
template
>
</view>
</view>
</template>
<
script
>
/**
* @description 输入验证码组件
* @property {string} type = [box|middle|bottom] - 显示类型 默认:box -eg:bottom
* @property {string} inputType = [text|number] - 输入框类型 默认:number -eg:number
* @property {number} size = [1|2|3|4|5|6] - 支持的验证码数量 默认:6 -eg:6
* @property {boolean} isFocus - 是否立即聚焦 默认:true
* @property {boolean} isPassword - 是否以密码形式显示 默认false -eg:false
* @property {string} cursorColor - 光标颜色 默认:#cccccc
* @property {string} boxNormalColor - 光标未聚焦到的框的颜色 默认:#cccccc
* @property {string} boxActiveColor - 光标聚焦到的框的颜色 默认:#000000
* @event {Function(data)} confirm - 输入完成
*/
export
default
{
name
:
'xt-verify-code'
,
props
:
{
value
:
{
type
:
String
,
default
:
()
=>
''
},
type
:
{
type
:
String
,
default
:
()
=>
'box'
},
inputType
:
{
type
:
String
,
default
:
()
=>
'number'
},
size
:
{
type
:
Number
,
default
:
()
=>
6
},
isFocus
:
{
type
:
Boolean
,
default
:
()
=>
false
},
isPassword
:
{
type
:
Boolean
,
default
:
()
=>
false
},
cursorColor
:
{
type
:
String
,
default
:
()
=>
'#cccccc'
},
boxNormalColor
:
{
type
:
String
,
default
:
()
=>
'#9f9f9f'
},
boxActiveColor
:
{
type
:
String
,
default
:
()
=>
'#ffffff'
}
},
model
:
{
prop
:
'value'
,
event
:
'input'
},
data
()
{
return
{
cursorVisible
:
false
,
cursorHeight
:
35
,
code
:
''
,
// 输入的验证码
codeCursorLeft
:
[],
// 向左移动的距离数组,
itemSize
:
6
};
},
created
()
{
this
.
cursorVisible
=
this
.
isFocus
;
this
.
validatorSize
();
},
mounted
()
{
this
.
init
();
},
methods
:
{
/**
*
*/
validatorSize
()
{
if
(
this
.
size
<=
6
&&
this
.
size
>
0
)
{
this
.
itemSize
=
Math
.
floor
(
this
.
size
);
}
else
{
this
.
itemSize
=
6
;
}
},
/**
* @description 初始化
*/
init
()
{
this
.
getCodeCursorLeft
();
this
.
setCursorHeight
();
},
/**
* @description 获取元素节点
* @param {string} elm - 节点的id、class 相当于 document.querySelect的参数 -eg: #id
* @param {string} type = [single|array] - 单个元素获取多个元素 默认是单个元素
* @param {Function} callback - 回调函数
*/
getElement
(
elm
,
type
=
'single'
,
callback
)
{
uni
.
createSelectorQuery
()
.
in
(
this
)
[
type
===
'array'
?
'selectAll'
:
'select'
](
elm
)
.
boundingClientRect
()
.
exec
(
data
=>
{
callback
(
data
[
0
]);
});
},
/**
* @description 计算光标的高度
*/
setCursorHeight
()
{
this
.
getElement
(
'.verify-code-box'
,
'single'
,
boxElm
=>
{
this
.
cursorHeight
=
boxElm
.
height
*
0.6
;
});
},
/**
* @description 获取光标在每一个box的left位置
*/
getCodeCursorLeft
()
{
// 获取父级框的位置信息
this
.
getElement
(
'.verify-code-ground'
,
'single'
,
parentElm
=>
{
const
parentLeft
=
parentElm
.
left
;
// 获取各个box信息
this
.
getElement
(
'.verify-code-box'
,
'array'
,
elms
=>
{
this
.
codeCursorLeft
=
[];
elms
.
forEach
(
elm
=>
{
this
.
codeCursorLeft
.
push
(
elm
.
left
-
parentLeft
+
elm
.
width
/
2
);
});
});
});
},
// 输入框输入变化的回调
input
(
e
)
{
const
value
=
e
.
detail
.
value
;
this
.
cursorVisible
=
value
.
length
!==
this
.
itemSize
;
this
.
$emit
(
'input'
,
value
);
this
.
inputSuccess
(
value
);
},
// 输入完成回调
inputSuccess
(
value
)
{
if
(
value
.
length
===
this
.
itemSize
)
{
this
.
$emit
(
'confirm'
,
value
);
}
},
// 输入聚焦
inputFocus
()
{
this
.
cursorVisible
=
this
.
code
.
length
!==
this
.
itemSize
;
},
// 输入失去焦点
inputBlur
()
{
this
.
cursorVisible
=
false
;
}
},
watch
:
{
value
(
val
)
{
this
.
code
=
val
;
}
},
filters
:
{
codeFormat
(
val
,
isPassword
)
{
let
value
=
''
;
if
(
val
)
{
value
=
isPassword
?
'*'
:
val
;
}
return
value
;
}
}
};
</
script
>
<
style
lang=
"scss"
scoped
>
.verify-code
{
position
:
relative
;
width
:
100%
;
box-sizing
:
border-box
;
&
-input
{
height
:
100%
;
width
:
200%
;
position
:
absolute
;
left
:
-100%
;
z-index
:
1
;
}
&
-cursor
{
position
:
absolute
;
top
:
50%
;
transform
:
translateY
(
-50%
);
display
:
inline-block
;
width
:
2px
;
animation-name
:
cursor
;
animation-duration
:
0
.8s
;
animation-iteration-count
:
infinite
;
}
&
-ground
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
width
:
100%
;
box-sizing
:
border-box
;
}
&
-box
{
position
:
relative
;
display
:
inline-block
;
color
:
white
;
width
:
100rpx
;
height
:
120rpx
;
&
-bottom
{
border-bottom-width
:
2px
;
border-bottom-style
:
solid
;
}
&
-box
{
border-width
:
2rpx
;
border-style
:
solid
;
border-radius
:
16rpx
;
}
&
-middle
{
border
:
none
;
}
}
&
-line
{
position
:
absolute
;
top
:
50%
;
left
:
50%
;
width
:
50%
;
transform
:
translate
(
-50%
,
-50%
);
border-bottom-width
:
2px
;
border-bottom-style
:
solid
;
}
&
-text
{
position
:
absolute
;
top
:
50%
;
left
:
50%
;
font-size
:
80rpx
;
transform
:
translate
(
-50%
,
-50%
);
}
}
@keyframes
cursor
{
0
%
{
opacity
:
1
;
}
100
%
{
opacity
:
0
;
}
}
</
style
>
vedio/components/video-loading/video-loading.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<u-popup
bgColor=
"transparent"
:show=
"showLoading"
mode=
"center"
:closeOnClickOverlay=
"false"
@
close=
"close"
>
<view
class=
"container"
>
<u-icon
name=
"close-circle"
color=
"#fff"
size=
"30"
@
click=
"close"
></u-icon>
<video
class=
"video-wrap"
objectFit=
"cover"
:controls=
"false"
:autoplay=
"true"
:loop=
"true"
@
loadedmetadata=
"videoMeta"
:style=
"'width:'+videoWidth+'px;height:'+videoHeight+'px'"
:src=
"videoUrl"
/>
<image
class=
"mt-30"
mode=
"widthFix"
:style=
"'width:'+videoWidth+'px;'"
:src=
"imageUrl"
></image>
</view>
</u-popup>
</
template
>
<
script
>
export
default
{
name
:
"video-loading"
,
props
:
{
show
:
{
type
:
Boolean
,
default
:
false
},
imgUrl
:
{
type
:
String
,
default
:
''
},
},
data
()
{
return
{
showLoading
:
this
.
show
,
videoUrl
:
'http://mints-sh.oss-cn-shanghai.aliyuncs.com/video/process.mp4'
,
videoWidth
:
''
,
videoHeight
:
''
,
imageUrl
:
this
.
imgUrl
,
};
},
watch
:
{
show
:
{
handler
:
function
(
newVal
,
oldVal
)
{
this
.
showLoading
=
newVal
;
}
},
imgUrl
:
{
handler
:
function
(
newVal
,
oldVal
)
{
this
.
imageUrl
=
newVal
;
}
}
},
methods
:
{
close
()
{
this
.
showLoading
=
false
this
.
$emit
(
'dismiss'
);
},
videoMeta
:
function
(
e
)
{
var
that
=
this
;
//获取系统信息
uni
.
getSystemInfo
({
success
(
res
)
{
//算出视频的比例
var
proportion
=
e
.
detail
.
height
/
e
.
detail
.
width
;
//res.windowWidth为手机屏幕的宽。
var
windowWidth
=
res
.
windowWidth
;
var
windowHeight
=
res
.
windowHeight
;
//算出当前宽度下高度的数值
that
.
videoHeight
=
proportion
*
windowWidth
;
that
.
videoWidth
=
windowWidth
*
(
that
.
videoHeight
/
windowWidth
);
}
})
},
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.container
{
display
:
flex
;
// justify-content: center;
flex-direction
:
column
;
max-height
:
1000rpx
;
border-top-left-radius
:
50rpx
;
border-top-right-radius
:
50rpx
;
}
.video-wrap
{
margin
:
50rpx
100rpx
;
border-radius
:
30rpx
;
}
image
{
margin
:
20rpx
100rpx
;
}
</
style
>
vedio/mixins/common.js
View file @
dbf68494
import
{
import
{
navigateTo
,
navigateTo
,
redirectTo
,
redirectTo
,
loading
,
loading
,
message
,
message
,
confirm
,
confirm
,
alert
alert
}
from
'../utils/fun.js'
;
}
from
'../utils/fun.js'
;
const
app
=
getApp
();
import
{
apiPOST
export
default
{
}
from
'../common/utils/apiRequest.js'
data
()
{
return
{
const
app
=
getApp
();
xhrPool
:
new
Set
(),
bottomSafePadding
:
app
.
globalData
.
bottomSafePadding
,
export
default
{
options
:
{},
data
()
{
auth
:
false
,
// 登录验证
return
{
paying
:
false
,
// 支付按钮状态
xhrPool
:
new
Set
(),
};
bottomSafePadding
:
app
.
globalData
.
bottomSafePadding
,
},
options
:
{},
onLoad
(
options
)
{
auth
:
false
,
// 登录验证
this
.
options
=
options
;
paying
:
false
,
// 支付按钮状态
};
},
},
onShow
()
{
onLoad
(
options
)
{
this
.
loadData
();
this
.
options
=
options
;
},
onHide
()
{
},
if
(
this
.
xhrPool
.
size
)
{
onShow
()
{
this
.
xhrPool
.
forEach
((
requestTask
)
=>
{
this
.
loadData
();
requestTask
.
abort
();
},
})
onHide
()
{
}
if
(
this
.
xhrPool
.
size
)
{
},
this
.
xhrPool
.
forEach
((
requestTask
)
=>
{
methods
:
{
requestTask
.
abort
();
authTo
(
url
)
{
//登录校验
})
}
},
},
authToNs
(
url
)
{
//登录校验不保留当前页面
methods
:
{
authTo
(
url
)
{
//登录校验
},
loadData
()
{},
},
startPay
()
{
authToNs
(
url
)
{
//登录校验不保留当前页面
loading
.
show
();
this
.
paying
=
true
;
},
},
loadData
()
{},
stopPay
()
{
startPay
()
{
loading
.
hide
();
loading
.
show
();
this
.
paying
=
false
;
this
.
paying
=
true
;
},
},
/**
stopPay
()
{
* @param {Object} url 接口请求地址
loading
.
hide
();
* @param {Object} method 接口请求方式
this
.
paying
=
false
;
* @param {Object} data 接口请求参数
},
*/
/**
$http
(
url
,
method
,
data
=
{},
showLoading
=
false
)
{
* @param {Object} url 接口请求地址
return
new
Promise
((
resolve
,
reject
)
=>
{
* @param {Object} method 接口请求方式
this
[
method
.
toLowerCase
()]({
* @param {Object} data 接口请求参数
url
:
url
,
*/
data
:
data
,
$http
(
url
,
method
,
data
=
{},
showLoading
=
false
)
{
showLoading
:
showLoading
,
return
new
Promise
((
resolve
,
reject
)
=>
{
success
:
(
res
)
=>
{
this
[
method
.
toLowerCase
()]({
resolve
(
res
)
url
:
url
,
},
data
:
data
,
fail
:
(
e
)
=>
{
showLoading
:
showLoading
,
reject
(
e
)
success
:
(
res
)
=>
{
}
resolve
(
res
)
});
},
})
fail
:
(
e
)
=>
{
},
reject
(
e
)
login
()
{
}
// navigateTo('user/login');
});
// let redirect = this.$scope.$page.fullPath.replace('/pages', '');
})
// console.log(redirect)
},
// navigateTo('user/login?redirect=' + encodeURIComponent(redirect));
login
()
{
},
// navigateTo('user/login');
logout
()
{
// let redirect = this.$scope.$page.fullPath.replace('/pages', '');
uni
.
removeStorageSync
(
'token'
);
// console.log(redirect)
},
// navigateTo('user/login?redirect=' + encodeURIComponent(redirect));
put
(
options
)
{
},
options
=
Object
.
assign
({
logout
()
{
showLoading
:
true
uni
.
removeStorageSync
(
'token'
);
},
options
,
{
},
method
:
'PUT'
post
(
options
)
{
})
options
=
Object
.
assign
({
this
.
req
(
options
);
showLoading
:
true
},
},
options
,
{
post
(
options
)
{
method
:
'POST'
options
=
Object
.
assign
({
})
showLoading
:
true
this
.
req
(
options
);
},
options
,
{
},
method
:
'POST'
// get(options) {
})
// options = Object.assign({
this
.
req
(
options
);
// showLoading: false
},
// }, options, {
get
(
options
)
{
// method: 'GET'
options
=
Object
.
assign
({
// })
showLoading
:
false
// this.req(options);
},
options
,
{
// },
method
:
'GET'
req
(
options
)
{
})
let
{
this
.
req
(
options
);
showLoading
,
},
url
,
req
(
options
)
{
data
,
let
{
auth
showLoading
,
}
=
options
;
url
,
data
,
const
success
=
options
?.
success
;
auth
const
fail
=
options
?.
fail
;
}
=
options
;
const
header
=
options
?.
header
??
{};
const
success
=
options
?.
success
;
showLoading
&&
loading
.
show
();
const
fail
=
options
?.
fail
;
const
header
=
options
?.
header
??
{};
apiPOST
({
url
:
`
${
url
}
`
,
showLoading
&&
loading
.
show
();
data
:
data
,
callback
:
(
_success
,
_data
)
=>
{
let
requestTask
;
showLoading
&&
loading
.
hide
();
let
uniChannel
=
'wechat'
;
if
(
_success
)
{
success
({
// #ifdef MP-KUAISHOU
data
:
_data
uniChannel
=
'kuaishou'
;
})
// #endif
}
else
{
fail
(
_data
)
// #ifdef MP-TOUTIAO
message
.
notify
(
res
.
data
.
message
);
uniChannel
=
'douyin'
;
}
// #endif
}
})
Object
.
assign
(
header
,
{
}
token
:
uni
.
getStorageSync
(
'token'
),
}
pkgName
:
app
.
globalData
.
pkgName
,
};
proChannel
:
uniChannel
\ No newline at end of file
})
options
=
Object
.
assign
(
options
,
{
url
:
`
${
app
.
globalData
.
baseUrl
}${
url
}
`
,
header
,
data
,
success
:
(
res
)
=>
{
showLoading
&&
loading
.
hide
();
switch
(
res
.
data
.
status
)
{
case
200
:
if
(
success
)
{
success
(
res
.
data
);
}
break
;
default
:
if
(
fail
)
{
fail
(
res
.
data
.
message
);
}
message
.
notify
(
res
.
data
.
message
);
break
;
}
},
fail
:
(
e
)
=>
{
message
.
notify
(
'服务器开小差了'
);
// alert({
// content: JSON.stringify(e)
// });
if
(
fail
)
{
fail
(
e
);
}
},
complete
:
()
=>
{
this
.
xhrPool
.
delete
(
requestTask
)
}
})
requestTask
=
uni
.
request
(
options
);
this
.
xhrPool
.
add
(
requestTask
)
}
}
};
vedio/page-subs/sub_A/read-history/components/history-item.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view
class=
"history-item"
@
click=
"tapItem"
>
<view
class=
"row"
>
<view
class=
"item c-flex_1"
>
<view
class=
"title"
>
{{
item
.
title
}}
</view>
</view>
</view>
<view
class=
"row"
>
<view
class=
"item c-flex_1"
>
<view
class=
"desc"
>
{{
item
.
summary
}}
</view>
</view>
</view>
<view
class=
"row c-justify_between"
>
<view
class=
"item"
>
<view
class=
"author-box"
>
<uni-icons
type=
'icon-author'
custom-prefix=
"readiconfont"
size=
'20'
color=
"#378eff"
></uni-icons>
<view
class=
"name"
>
{{
item
.
author
}}
</view>
</view>
</view>
<view
class=
"item"
@
click
.
stop=
"tapCollection(item.isCollect)"
>
<view
class=
"collection-button collected"
v-if=
'item.isCollect'
>
<uni-icons
type=
'checkmarkempty'
size=
'10'
color=
"#999"
></uni-icons>
<view
class=
"title"
>
已添加
</view>
</view>
<view
class=
"collection-button"
v-else
>
<uni-icons
type=
'icon-collection'
custom-prefix=
"readiconfont"
size=
'10'
color=
'#378eff'
></uni-icons>
<view
class=
"title"
>
加入书架
</view>
</view>
</view>
</view>
</view>
</
template
>
<
script
>
export
default
{
props
:
{
item
:
{
type
:
Object
,
default
:
function
()
{
return
{}
}
}
},
methods
:
{
tapItem
()
{
this
.
$emit
(
'tapItem'
,
{
detail
:
{
data
:
this
.
item
}
})
},
tapCollection
(
isCollect
)
{
this
.
$emit
(
'changeCollection'
,
{
detail
:
{
data
:
this
.
item
,
isCollection
:
!
isCollect
}
})
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.history-item
{
padding
:
30rpx
;
display
:
flex
;
flex-direction
:
column
;
.row
{
margin-bottom
:
20rpx
;
display
:
flex
;
flex-direction
:
row
;
}
.row
:last-child
{
margin-bottom
:
0
;
}
.item
{
margin-right
:
20rpx
;
display
:
flex
;
flex-direction
:
column
;
}
.item
:last-child
{
margin-right
:
0
;
}
.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
;
}
}
.collection-button
{
height
:
50rpx
;
line-height
:
50rpx
;
width
:
150rpx
;
display
:
flex
;
flex-direction
:
row
;
align-items
:
center
;
justify-content
:
center
;
background-color
:
#a0c9ff
;
border-radius
:
10rpx
;
.title
{
font-size
:
22rpx
;
color
:
#378eff
;
margin-left
:
10rpx
;
}
}
.collected
{
background-color
:
#ededed
;
.title
{
color
:
#999
;
}
}
}
</
style
>
\ No newline at end of file
vedio/page-subs/sub_A/read-history/models/ReadHistory.js
deleted
100644 → 0
View file @
abb53a01
import
Book
from
"../../../../common/models/Book"
;
export
default
class
ReadHistory
extends
Book
{
constructor
(
param
)
{
super
(
param
)
}
}
\ No newline at end of file
vedio/page-subs/sub_A/read-history/read-history.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view>
<c-list
ref=
'list'
flag=
'readHistory'
:needLogin=
"true"
method=
"POST"
url=
'/readSystem/system/readRecord/list'
:param=
"requestParam"
@
change=
'changeData'
>
<history-item
v-for=
"(item, index) in dataList"
:key=
"index"
:item=
'item'
@
tapItem=
'tapItem($event, index)'
@
changeCollection=
'changeCollection($event, index)'
></history-item>
</c-list>
<c-login></c-login>
</view>
</
template
>
<
script
>
import
{
isEmpty
}
from
'../../../common/utils/util'
;
import
ReadHistory
from
'./models/ReadHistory'
;
import
HistoryItem
from
"./components/history-item.vue"
;
import
{
gotoBookContentPage
}
from
'../../../common/services/page-route'
;
import
{
collectionBook
}
from
"../../../common/services/index.js"
import
{
watchUserInfoChange
,
removeUserInfoChangeWatch
,
}
from
"../../../common/services/userServices.js"
;
import
{
noticeCollectionListChange
,
removeCollectionChangeWatch
,
watchCollectionChange
}
from
'../../../common/services'
;
export
default
{
components
:
{
HistoryItem
},
data
()
{
return
{
dataList
:
[],
isFirstRequest
:
false
};
},
computed
:
{
requestParam
:
function
()
{
return
{}
}
},
onReady
()
{
watchUserInfoChange
((
info
)
=>
{
if
(
info
.
userInfo
)
{
this
.
initRefresh
();
}
},
this
)
watchCollectionChange
((
info
)
=>
{
let
index
=
0
;
let
item
;
let
changeItem
;
for
(;
index
<
this
.
dataList
.
length
;
index
++
)
{
item
=
this
.
dataList
[
index
];
if
(
item
.
id
==
info
.
bookId
)
{
item
.
isCollect
=
info
.
isCollect
;
changeItem
=
item
;
break
;
}
}
if
(
changeItem
)
{
this
.
$set
(
this
.
dataList
,
index
,
changeItem
);
}
},
this
)
},
onUnload
()
{
removeUserInfoChangeWatch
(
this
);
removeCollectionChangeWatch
(
this
);
},
methods
:
{
initRefresh
()
{
if
(
isEmpty
(
this
.
dataList
))
{
this
.
refreshList
();
}
},
refreshList
()
{
let
ref
=
this
.
$refs
.
list
;
if
(
ref
)
{
ref
.
onPullRefreshing
();
}
},
changeData
(
e
)
{
this
.
dataList
=
e
.
detail
.
data
.
map
(
item
=>
{
return
new
ReadHistory
(
item
)
})
},
tapItem
(
e
,
index
)
{
let
item
=
e
.
detail
.
data
;
gotoBookContentPage
(
item
.
id
);
},
changeCollection
(
e
,
index
)
{
let
item
=
e
.
detail
.
data
;
let
target
=
e
.
detail
.
isCollection
;
// TODO 发请求,改变收藏状态,success 后修改页面
collectionBook
(
target
,
item
.
id
,
(
success
,
data
)
=>
{
if
(
success
)
{
item
.
isCollect
=
target
;
this
.
$set
(
this
.
dataList
,
index
,
new
ReadHistory
(
item
));
noticeCollectionListChange
(
item
.
id
,
target
);
}
})
}
}
}
</
script
>
<
style
lang=
"scss"
>
</
style
>
\ No newline at end of file
vedio/page-subs/sub_B/book-bean-detail/book-bean-detail.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view>
<book-bean-header
id=
'header'
:beanCount=
'beanCount'
></book-bean-header>
<view
id=
'title'
class=
"c-flex_row c-align_center"
>
<view
class=
"section-title"
>
书豆明细
</view>
<view
class=
"recharge-button"
@
click=
"tapRecharge"
>
前往充值
</view>
</view>
<c-list
ref=
'list'
flag=
'bookBeanDetail'
:needLogin=
"true"
:height=
"listHeight"
url=
'//system/bookLegumesRecord/list'
method=
"POST"
bgColor=
"transparent"
:param=
"
{}"
@change='changeData'>
<view
class=
"record-item"
v-for=
'(item, index) in dataList'
:key=
"index"
@
click=
"tapRecord(item)"
>
<view
class=
"row"
>
<view
class=
"desc"
>
{{
item
.
recordDescription
}}
</view>
<view
class=
"value"
>
{{
item
.
bookLegumes
}}
</view>
</view>
<view
class=
"row"
>
<view
class=
"time"
>
{{
item
.
createTime
}}
</view>
</view>
</view>
</c-list>
<c-login></c-login>
</view>
</
template
>
<
script
>
import
BookBeanHeader
from
"./components/book-bean-header.vue"
import
SystemInfoMixin
from
"../../../common/mixins/system-info-mixin.js"
;
import
{
watchUserInfoChange
,
removeUserInfoChangeWatch
,
}
from
"../../../common/services/userServices.js"
import
BookBeanRecordItem
from
"./models/BookBeanRecordItem"
;
import
{
gotoBookBeanRechargePage
,
gotoBookContentPage
}
from
"../../../common/services/page-route"
;
export
default
{
mixins
:
[
SystemInfoMixin
],
components
:
{
BookBeanHeader
},
data
()
{
return
{
userInfo
:
null
,
listHeight
:
0
,
dataList
:
[]
}
},
computed
:
{
beanCount
:
function
()
{
if
(
this
.
userInfo
)
return
this
.
userInfo
.
bookLegumes
;
return
0
;
}
},
onReady
()
{
watchUserInfoChange
((
info
)
=>
{
this
.
userInfo
=
info
.
userInfo
// 已登录,自动刷新
if
(
this
.
userInfo
)
{
this
.
refreshList
();
}
},
this
)
this
.
$nextTick
(()
=>
{
this
.
initListHeight
();
})
},
onUnload
()
{
removeUserInfoChangeWatch
(
this
);
},
methods
:
{
// 初始化列表高度
initListHeight
()
{
const
query
=
uni
.
createSelectorQuery
().
in
(
this
);
query
.
select
(
"#header"
).
boundingClientRect
();
query
.
select
(
"#title"
).
boundingClientRect
();
query
.
exec
((
res
)
=>
{
let
result
=
this
.
windowHeight
;
res
.
forEach
(
item
=>
{
result
=
result
-
item
.
height
;
})
this
.
listHeight
=
result
;
})
},
// 开始列表刷新
refreshList
()
{
let
ref
=
this
.
$refs
.
list
;
if
(
ref
)
{
ref
.
onPullRefreshing
();
}
},
// 列表数据变动
changeData
(
e
)
{
this
.
dataList
=
e
.
detail
.
data
.
map
(
item
=>
{
return
new
BookBeanRecordItem
(
item
);
})
},
// 点击充值
tapRecharge
()
{
gotoBookBeanRechargePage
()
},
// 点击记录
tapRecord
(
record
)
{
if
(
record
.
articleId
)
{
gotoBookContentPage
(
record
.
articleId
);
}
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.section-title
{
flex
:
1
;
margin
:
20rpx
30rpx
;
font-weight
:
700
;
}
.recharge-button
{
margin
:
20rpx
30rpx
;
height
:
60rpx
;
line-height
:
60rpx
;
width
:
150rpx
;
font-size
:
28rpx
;
background
:
#fff6cd
;
color
:
#b26605
;
border-radius
:
30rpx
;
text-align
:
center
;
}
.record-item
{
margin
:
30rpx
;
margin-bottom
:
0
;
background
:
#fff
;
.row
{
margin
:
20rpx
;
margin-bottom
:
0
;
display
:
flex
;
flex-direction
:
row
;
align-items
:
center
;
}
.row
:last-child
{
margin-bottom
:
20rpx
;
}
.desc
{
font-size
:
30rpx
;
color
:
#333
;
flex
:
1
;
}
.value
{
font-size
:
36rpx
;
color
:
#ff2525
;
font-weight
:
700
;
}
.
value
:
:
before
{
content
:
"-"
}
.time
{
font-size
:
26rpx
;
color
:
#999
;
}
}
.recommond-item
:last-child
{
margin-bottom
:
30rpx
;
}
</
style
>
\ No newline at end of file
vedio/page-subs/sub_B/book-bean-detail/components/book-bean-header.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view
class=
"book-bean-header"
>
<view
class=
"bg"
>
<view
class=
"bg-1 bg-cricle"
></view>
<view
class=
"bg-2 bg-cricle"
></view>
<view
class=
"bg-3 bg-cricle"
></view>
<view
class=
"bean-logo"
>
<image
class=
"bean"
:src=
"beanLogoSrc"
mode=
"aspectFit"
></image>
</view>
</view>
<view
class=
"content"
>
<view
class=
"title row"
v-if=
'ready'
>
书豆余额
</view>
<view
class=
"value row"
v-if=
'ready'
>
{{
beanCount
}}
</view>
<view
class=
"footter row"
v-if=
'ready'
>
<slot></slot>
</view>
</view>
</view>
</
template
>
<
script
>
export
default
{
props
:
{
beanLogoSrc
:
{
type
:
String
,
default
:
"/static/images/book-bean/book-bean-2.png"
},
beanCount
:
{
type
:
Number
,
default
:
0
}
},
data
:
function
()
{
return
{
ready
:
false
}
},
mounted
()
{
setTimeout
(()
=>
{
this
.
ready
=
true
},
500
)
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.book-bean-header
{
margin
:
30rpx
;
border-radius
:
40rpx
;
background
:
transparent
;
box-shadow
:
0
20rpx
20rpx
#888888
44
;
position
:
relative
;
.bg
{
position
:
absolute
;
top
:
0
;
left
:
0
;
right
:
0
;
bottom
:
0
;
background
:
#fff6cd
;
border-radius
:
40rpx
;
overflow
:
hidden
;
.bg-cricle
{
position
:
absolute
;
bottom
:
0
;
right
:
0
;
border-radius
:
50%
;
transform
:
translate
(
50%
,
50%
);
z-index
:
0
;
}
.bg-1
{
height
:
900rpx
;
width
:
900rpx
;
background
:
#fff4b0
;
}
.bg-2
{
height
:
700rpx
;
width
:
700rpx
;
background
:
#ffefaf
;
}
.bg-3
{
height
:
500rpx
;
width
:
500rpx
;
background
:
#ffef9c
;
}
.bean-logo
{
position
:
absolute
;
padding
:
40rpx
;
top
:
0
;
right
:
0
;
bottom
:
0
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
.bean
{
width
:
200rpx
;
height
:
200rpx
;
}
}
}
.content
{
padding
:
60rpx
40rpx
;
color
:
#372705
;
position
:
relative
;
min-height
:
200rpx
;
background
:
transparent
;
.row
{
margin-bottom
:
30rpx
;
z-index
:
5
;
}
.row
:last-child
{
margin-bottom
:
0
;
}
.title
{}
.value
{
font-size
:
56rpx
;
font-weight
:
700
;
}
.footer
{}
}
}
</
style
>
\ No newline at end of file
vedio/page-subs/sub_B/book-bean-detail/models/BookBeanRecordItem.js
deleted
100644 → 0
View file @
abb53a01
export
default
class
BookBeanRecordItem
{
constructor
(
param
)
{
const
{
id
,
userId
,
articleId
,
bookLegumes
,
recordDescription
,
createTime
}
=
param
||
{}
this
.
id
=
id
;
this
.
userId
=
userId
;
this
.
articleId
=
articleId
;
this
.
bookLegumes
=
bookLegumes
;
this
.
recordDescription
=
recordDescription
;
this
.
createTime
=
createTime
;
}
}
\ No newline at end of file
vedio/page-subs/sub_B/book-bean-recharge/book-bean-recharge.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view>
<book-bean-header
id=
'header'
beanLogoSrc=
'/static/images/book-bean/book-bean-1.png'
:beanCount=
'beanCount'
>
<view
class=
"desc"
>
使用书豆可以单独购买指定书籍
</view>
</book-bean-header>
<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>
<c-login></c-login>
</view>
</
template
>
<
script
>
import
{
watchUserInfoChange
,
removeUserInfoChangeWatch
,
showLoginView
,
refreshUserInfo
}
from
"../../../common/services/userServices.js"
import
BookBeanHeader
from
"../book-bean-detail/components/book-bean-header.vue"
import
{
getBookBeanPackData
,
getOpenId
,
getPayInfo
,
ENUM_PAY_TYPE
}
from
"../../../common/services/index.js"
import
PayInfo
from
"../../../common/models/PayInfo.js"
import
BookBeanPack
from
"../../../common/models/BookBeanPack.js"
import
{
toastMessage
}
from
"../../../common/utils/toastUtil.js"
;
export
default
{
components
:
{
BookBeanHeader
},
data
()
{
return
{
userInfo
:
null
,
packData
:
[],
selectedIndex
:
0
,
loading
:
false
}
},
computed
:
{
beanCount
:
function
()
{
if
(
this
.
userInfo
)
return
this
.
userInfo
.
bookLegumes
;
return
0
;
}
},
onReady
()
{
watchUserInfoChange
((
info
)
=>
{
this
.
userInfo
=
info
.
userInfo
;
},
this
)
uni
.
startPullDownRefresh
({
})
},
onUnload
()
{
removeUserInfoChangeWatch
(
this
);
},
onPullDownRefresh
()
{
this
.
requestPackData
();
},
methods
:
{
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
>
.desc
{
font-size
:
24rpx
;
}
.section
{
padding
:
0
30rpx
;
display
:
flex
;
flex-direction
:
column
;
background
:
transparent
;
.title
{
font-size
:
32rpx
;
font-weight
:
700
;
color
:
#333
;
margin-bottom
:
30rpx
;
}
.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
:
#fff
;
border
:
6rpx
solid
#fff
;
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_B/feedback/feedback.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view>
<view
style=
"margin: 24rpx;font-size: 30rpx;color: black;"
>
请输入要反馈的内容:
</view>
<view
style=
"margin: 20rpx;"
>
<uni-easyinput
type=
"textarea"
@
input=
"input"
v-model=
"inputClearValue"
placeholder=
"请留下您的批评,表扬或者建议,我们会虚心听取,认真改正."
></uni-easyinput>
</view>
<button
class=
"apply-button"
@
click=
"cmtFeedback()"
>
提交
</button>
</view>
</
template
>
<
script
>
import
{
toastMessage
}
from
"../../../common/utils/toastUtil.js"
;
import
{
getFeedback
}
from
"../../../common/services/index.js"
;
export
default
{
data
()
{
return
{
inputClearValue
:
''
};
},
methods
:
{
input
(
e
)
{
this
.
inputClearValue
=
e
;
},
cmtFeedback
(){
if
(
this
.
inputClearValue
.
length
==
0
){
toastMessage
(
'请输入内容'
)
return
;
}
getFeedback
(
this
.
inputClearValue
,(
success
,
data
)
=>
{
if
(
success
)
{
toastMessage
(
'反馈成功'
);
this
.
inputClearValue
=
''
;
}
})
}
}
}
</
script
>
<
style
>
.apply-button
{
border-radius
:
50
rpx
;
background
:
#e8c8ae
;
color
:
#8d5a29
;
margin
:
60
rpx
;
}
</
style
>
\ No newline at end of file
vedio/page-subs/sub_B/message/message.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view>
<c-tabs
id=
'tabs'
:tabs=
"typeList"
:value=
'typeIndex'
nameKey=
'name'
@
change=
'changeType'
></c-tabs>
<c-list
:height=
"listHeight"
:ableRefresh=
'false'
:ableLoadMore=
"false"
:needLogin=
'true'
></c-list>
<c-login></c-login>
</view>
</
template
>
<
script
>
import
{
ENUM_MESSAGE_PAGE_TYPE
}
from
'../../../static/enums/enum_value'
;
export
default
{
data
()
{
return
{
typeList
:
Object
.
keys
(
ENUM_MESSAGE_PAGE_TYPE
).
map
(
key
=>
{
return
ENUM_MESSAGE_PAGE_TYPE
[
key
]
}),
typeValue
:
ENUM_MESSAGE_PAGE_TYPE
.
SYS
.
value
,
typeIndex
:
0
,
listHeight
:
0
};
},
watch
:
{
typeValue
:
{
handler
:
function
(
n
)
{
this
.
typeList
.
forEach
((
item
,
index
)
=>
{
if
(
item
.
value
==
n
)
{
this
.
typeIndex
=
index
;
uni
.
setNavigationBarTitle
({
title
:
item
.
name
})
}
})
}
}
},
onReady
()
{
uni
.
setNavigationBarTitle
({
title
:
ENUM_MESSAGE_PAGE_TYPE
.
SYS
.
name
})
const
eventChannel
=
this
.
getOpenerEventChannel
();
eventChannel
.
on
(
"openMessagePage"
,
(
info
)
=>
{
this
.
typeValue
=
info
.
type
;
})
this
.
initListHeight
();
},
methods
:
{
initListHeight
()
{
const
query
=
uni
.
createSelectorQuery
().
in
(
this
);
query
.
select
(
"#tabs"
).
boundingClientRect
().
exec
((
res
)
=>
{
let
result
=
uni
.
getSystemInfoSync
().
windowHeight
;
res
.
forEach
(
item
=>
{
if
(
item
&&
item
.
height
)
{
result
=
result
-
item
.
height
}
})
this
.
listHeight
=
result
;
})
},
changeType
(
e
)
{
this
.
typeValue
=
e
.
value
;
}
}
}
</
script
>
<
style
lang=
"scss"
>
</
style
>
\ No newline at end of file
vedio/page-subs/sub_B/read-preference/read-preference.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view>
<view
class=
"sex-box"
:class=
"
{active: maleActive}" @click="tapSexBox('male')">
<view
class=
"content-box"
>
<view
class=
"title-box"
>
<view
class=
"title"
>
男生小说
</view>
</view>
<image
class=
"logo"
src=
"/static/images/read-preference/male.png"
mode=
"aspectFit"
></image>
</view>
<view
class=
"selected-icon"
v-show=
"maleActive"
>
<uni-icons
type=
'checkbox-filled'
size=
'32'
color=
"#FECF02"
></uni-icons>
</view>
</view>
<view
class=
"sex-box"
:class=
"
{active: femaleActive}" @click="tapSexBox('female')">
<view
class=
"content-box"
>
<view
class=
"title-box"
>
<view
class=
"title"
>
女生小说
</view>
</view>
<image
class=
"logo"
src=
"/static/images/read-preference/female.png"
mode=
"aspectFit"
></image>
</view>
<view
class=
"selected-icon"
v-show=
"femaleActive"
>
<uni-icons
type=
'checkbox-filled'
size=
'32'
color=
"#FECF02"
></uni-icons>
</view>
</view>
<c-login></c-login>
</view>
</
template
>
<
script
>
import
{
readStorage
,
saveStorage
}
from
'../../../common/utils/storageUtil'
;
import
{
ENUM_SEX_TYPE
}
from
'../../../static/enums/enum_value'
;
export
default
{
computed
:
{
maleActive
:
function
()
{
return
this
.
sex
==
ENUM_SEX_TYPE
.
MALE
.
value
},
femaleActive
:
function
()
{
return
this
.
sex
==
ENUM_SEX_TYPE
.
FEMALE
.
value
}
},
data
()
{
return
{
sex
:
ENUM_SEX_TYPE
.
MALE
.
value
};
},
onReady
()
{
let
storageResult
=
readStorage
(
'readPreference'
);
if
(
!
storageResult
)
{
this
.
sex
=
ENUM_SEX_TYPE
.
MALE
.
value
}
else
{
this
.
sex
=
storageResult
;
}
},
methods
:
{
tapSexBox
(
type
)
{
switch
(
type
)
{
case
'male'
:
this
.
sex
=
ENUM_SEX_TYPE
.
MALE
.
value
break
;
case
'female'
:
this
.
sex
=
ENUM_SEX_TYPE
.
FEMALE
.
value
break
;
default
:
break
;
}
saveStorage
(
'readPreference'
,
this
.
sex
);
uni
.
showToast
({
title
:
"设置成功"
})
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
page
{
background-color
:
#fff
;
}
.sex-box
{
position
:
relative
;
width
:
270rpx
;
height
:
270rpx
;
border-radius
:
135rpx
;
background
:
#e4e4e4
;
margin
:
100rpx
auto
0
;
.content-box
{
width
:
260rpx
;
height
:
260rpx
;
border-radius
:
130rpx
;
overflow
:
hidden
;
display
:
flex
;
flex-direction
:
column
;
border
:
5rpx
solid
#f2f5f8
;
.title-box
{
flex
:
1
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
.title
{
font-size
:
30rpx
;
color
:
#333
;
text-align
:
center
;
}
}
.logo
{
width
:
150rpx
;
height
:
150rpx
;
margin
:
auto
;
}
}
.selected-icon
{
position
:
absolute
;
bottom
:
0
;
right
:
0
;
border-radius
:
50%
;
background
:
#fff
;
}
}
.sex-box
:first-child
{
margin-top
:
150rpx
;
}
.active
{
border
:
5rpx
solid
#FECF02
!
important
;
background
:
#f2f5f8
;
}
</
style
>
\ No newline at end of file
vedio/page-subs/sub_B/user-edit/components/edit-input-pop.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<uni-popup
ref=
'pop'
type=
"center"
:is-mask-click=
'false'
:safe-area=
'false'
@
maskClick=
'tapMask'
>
<view
class=
"input-box"
>
<view
class=
"row"
>
<uni-easyinput
v-model=
"inputValue"
:autoHeight=
'true'
:trim=
'true'
:maxlength=
"maxLength"
:placeholder=
"placeholder"
/>
</view>
<view
class=
"bottom-button-box row"
>
<button
class=
"c-button_clear c-button-size_base c-button-width_half cancel"
@
click=
"tapMask"
>
取消编辑
</button>
<button
class=
"c-button_clear c-button-size_base c-button-width_half confirm"
@
click=
"confirm"
>
确认编辑
</button>
</view>
</view>
</uni-popup>
</
template
>
<
script
>
export
default
{
props
:
{
value
:
{
type
:
String
,
default
:
""
},
placeholder
:
{
type
:
String
,
default
:
""
},
type
:
{
type
:
String
,
default
:
""
},
maxLength
:
{
type
:
Number
,
default
:
35
},
show
:
{
type
:
Boolean
,
default
:
false
}
},
data
:
function
()
{
return
{
showPop
:
false
,
inputValue
:
""
,
}
},
watch
:
{
show
:
function
(
n
)
{
this
.
showPop
=
n
;
},
showPop
:
function
(
n
,
o
)
{
if
(
n
==
o
)
return
;
if
(
n
)
{
this
.
open
();
}
else
{
this
.
close
();
}
},
value
:
{
handler
:
function
(
n
)
{
this
.
inputValue
=
n
;
},
immediate
:
true
}
},
methods
:
{
open
()
{
this
.
$refs
.
pop
.
open
();
},
close
()
{
this
.
$emit
(
'close'
)
this
.
$refs
.
pop
.
close
();
},
tapMask
()
{
this
.
showPop
=
false
;
},
confirm
()
{
this
.
$emit
(
"changeValue"
,
{
detail
:
{
value
:
this
.
inputValue
,
type
:
this
.
type
}
})
this
.
tapMask
();
}
},
}
</
script
>
<
style
lang=
"scss"
scoped
>
.input-box
{
display
:
flex
;
flex-direction
:
column
;
justify-content
:
space-around
;
padding
:
30rpx
;
background
:
#fff
;
border-radius
:
20rpx
;
min-width
:
600rpx
;
min-height
:
400rpx
;
.row
{
margin-bottom
:
20rpx
;
}
.row
:last-child
{
margin-bottom
:
0
;
}
.bottom-button-box
{
display
:
flex
;
flex-direction
:
row
;
align-items
:
center
;
.cancel
{
background
:
#dd524d
;
color
:
#fff
;
}
.confirm
{
background
:
#FECF02
;
color
:
#333
;
}
}
}
</
style
>
\ No newline at end of file
vedio/page-subs/sub_B/user-edit/services/index.js
deleted
100644 → 0
View file @
abb53a01
import
{
apiPOST
,
apiUPLOAD
}
from
"../../../../common/utils/apiRequest.js"
import
{
getSystemDict
,
ENUM_DICT_NAME
}
from
"../../../../common/services/index.js"
import
config
from
"../../../../config/index.js"
;
function
editUserInfo
(
userInfo
,
callback
)
{
let
data
=
{
...
userInfo
,
nickname
:
userInfo
.
nickName
,
avatar
:
userInfo
.
avater
,
intro
:
userInfo
.
sign
,
status
:
userInfo
.
status
,
sex
:
userInfo
.
sex
}
apiPOST
({
url
:
`/system/user/update`
,
data
,
callback
})
}
import
{
readToken
}
from
"../../../../common/services/userServices.js"
function
uploadAvater
(
filePath
,
callback
)
{
const
fileManager
=
uni
.
getFileSystemManager
();
fileManager
.
readFile
({
filePath
,
position
:
0
,
success
(
res
)
{
console
.
log
(
res
.
data
)
uni
.
request
({
url
:
`
${
config
[
"BASE_URL"
]}
/file/upload`
,
header
:
{
Authorization
:
`
${
readToken
()}
`
,
"content-type"
:
"multipart/form-data;"
,
},
data
:
res
.
data
,
method
:
"POST"
})
},
})
// apiUPLOAD({
// url: `/file/upload`,
// filePath,
// name: 'file',
// callback
// })
}
function
getSexDict
(
callback
)
{
getSystemDict
([
ENUM_DICT_NAME
.
SEX
],
(
success
,
data
)
=>
{
if
(
success
)
{
if
(
typeof
callback
==
'function'
)
callback
(
true
,
data
[
ENUM_DICT_NAME
.
SEX
].
list
)
}
else
{
if
(
typeof
callback
==
'function'
)
callback
(
false
)
}
});
}
module
.
exports
=
{
editUserInfo
,
uploadAvater
,
getSexDict
}
\ No newline at end of file
vedio/page-subs/sub_B/user-edit/user-edit.vue
deleted
100644 → 0
View file @
abb53a01
This diff is collapsed.
Click to expand it.
vedio/page-subs/sub_B/vip-apply/vip-apply.vue
deleted
100644 → 0
View file @
abb53a01
This diff is collapsed.
Click to expand it.
vedio/pages.json
View file @
dbf68494
This diff is collapsed.
Click to expand it.
vedio/pages/loading.vue
View file @
dbf68494
This diff is collapsed.
Click to expand it.
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