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
Show 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) {
})
}
// 阅读历史
function
gotoReadHistoryPage
()
{
uni
.
navigateTo
({
url
:
`/page-subs/sub_A/read-history/read-history`
})
}
// vip申请
function
gotoVIPApplyPage
()
{
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) {
})
}
// 消息
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
=
{
/** sub_A */
gotoBookSearchPage
,
gotoBookContentPage
,
gotoBookCoverPage
,
gotoReadHistoryPage
,
/** sub_B */
gotoVIPApplyPage
,
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) {
function
requestToken
(
data
,
callback
)
{
let
url
=
`
${
config
[
"BASE_URL"
]}
/user/ttLogin`
;
let
header
=
{
pkg
n
ame
:
PAKEAGE_NAME
,
pkg
N
ame
:
PAKEAGE_NAME
,
token
:
``
}
uni
.
request
({
...
...
@@ -168,7 +168,6 @@ function requestToken(data, callback) {
// 请求用户数据
function
requestUserInfo
(
callback
)
{
let
url
=
`
${
config
[
'BASE_URL'
]}
/user/baseMsg`
;
let
header
=
{}
let
uniChannel
=
'wechat'
;
...
...
@@ -181,8 +180,8 @@ function requestUserInfo(callback) {
// #endif
Object
.
assign
(
header
,
{
token
:
uni
.
getStorageSync
(
'token'
),
pkgName
:
app
.
globalData
.
pkgName
,
token
:
readToken
(
),
pkgName
:
PAKEAGE_NAME
,
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
<
template
>
<view
class=
"uni-file-picker"
>
<view
v-if=
"title"
class=
"uni-file-picker__header"
>
<text
class=
"file-title"
>
{{
title
}}
</text>
<text
class=
"file-count"
>
{{
filesList
.
length
}}
/
{{
limitLength
}}
</text>
</view>
<upload-image
v-if=
"fileMediatype === 'image' && showType === 'grid'"
:readonly=
"readonly"
:image-styles=
"imageStyles"
:files-list=
"filesList"
:limit=
"limitLength"
:disablePreview=
"disablePreview"
:delIcon=
"delIcon"
@
uploadFiles=
"uploadFiles"
@
choose=
"choose"
@
delFile=
"delFile"
>
<slot>
<view
class=
"add-wrap"
>
<u-icon
name=
"plus"
></u-icon>
<text>
上传图片
</text>
</view>
</slot>
</upload-image>
<upload-file
v-if=
"fileMediatype !== 'image' || showType !== 'grid'"
:readonly=
"readonly"
:list-styles=
"listStyles"
:files-list=
"filesList"
:showType=
"showType"
:delIcon=
"delIcon"
@
uploadFiles=
"uploadFiles"
@
choose=
"choose"
@
delFile=
"delFile"
>
<slot>
<view
v-if=
"filesList.length == 0"
class=
"add-wrap"
>
<u-icon
name=
"plus"
></u-icon>
<text>
上传视频
</text>
</view>
</slot>
</upload-file>
</view>
</
template
>
<
script
>
import
{
chooseAndUploadFile
,
uploadCloudFiles
}
from
'./choose-and-upload-file.js'
;
import
{
get_file_ext
,
get_extname
,
get_files_and_is_max
,
get_file_info
,
get_file_data
}
from
'./utils.js'
;
import
uploadImage
from
'./upload-image.vue'
;
import
uploadFile
from
'./upload-file.vue'
;
let
fileInput
=
null
;
/**
* FilePicker 文件选择上传
* @description 文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间
* @tutorial https://ext.dcloud.net.cn/plugin?id=4079
* @property {Object|Array} value 组件数据,通常用来回显 ,类型由return-type属性决定
* @property {Boolean} disabled = [true|false] 组件禁用
* @value true 禁用
* @value false 取消禁用
* @property {Boolean} readonly = [true|false] 组件只读,不可选择,不显示进度,不显示删除按钮
* @value true 只读
* @value false 取消只读
* @property {String} return-type = [array|object] 限制 value 格式,当为 object 时 ,组件只能单选,且会覆盖
* @value array 规定 value 属性的类型为数组
* @value object 规定 value 属性的类型为对象
* @property {Boolean} disable-preview = [true|false] 禁用图片预览,仅 mode:grid 时生效
* @value true 禁用图片预览
* @value false 取消禁用图片预览
* @property {Boolean} del-icon = [true|false] 是否显示删除按钮
* @value true 显示删除按钮
* @value false 不显示删除按钮
* @property {Boolean} auto-upload = [true|false] 是否自动上传,值为true则只触发@select,可自行上传
* @value true 自动上传
* @value false 取消自动上传
* @property {Number|String} limit 最大选择个数 ,h5 会自动忽略多选的部分
* @property {String} title 组件标题,右侧显示上传计数
* @property {String} mode = [list|grid] 选择文件后的文件列表样式
* @value list 列表显示
* @value grid 宫格显示
* @property {String} file-mediatype = [image|video|all] 选择文件类型
* @value image 只选择图片
* @value video 只选择视频
* @value all 选择所有文件
* @property {Array} file-extname 选择文件后缀,根据 file-mediatype 属性而不同
* @property {Object} list-style mode:list 时的样式
* @property {Object} image-styles 选择文件后缀,根据 file-mediatype 属性而不同
* @event {Function} select 选择文件后触发
* @event {Function} progress 文件上传时触发
* @event {Function} success 上传成功触发
* @event {Function} fail 上传失败触发
* @event {Function} delete 文件从列表移除时触发
*/
export
default
{
name
:
'uniFilePicker'
,
components
:
{
uploadImage
,
uploadFile
},
emits
:
[
'select'
,
'success'
,
'fail'
,
'progress'
,
'delete'
,
'update:modelValue'
,
'input'
],
props
:
{
// #ifdef VUE3
modelValue
:
{
type
:
[
Array
,
Object
],
default
()
{
return
[];
}
},
// #endif
// #ifndef VUE3
value
:
{
type
:
[
Array
,
Object
],
default
()
{
return
[];
}
},
// #endif
disabled
:
{
type
:
Boolean
,
default
:
false
},
disablePreview
:
{
type
:
Boolean
,
default
:
false
},
delIcon
:
{
type
:
Boolean
,
default
:
true
},
// 自动上传
autoUpload
:
{
type
:
Boolean
,
default
:
true
},
// 最大选择个数 ,h5只能限制单选或是多选
limit
:
{
type
:
[
Number
,
String
],
default
:
9
},
// 列表样式 grid | list | list-card
mode
:
{
type
:
String
,
default
:
'grid'
},
// 选择文件类型 image/video/all
fileMediatype
:
{
type
:
String
,
default
:
'image'
},
// 文件类型筛选
fileExtname
:
{
type
:
[
Array
,
String
],
default
()
{
return
[];
}
},
title
:
{
type
:
String
,
default
:
''
},
listStyles
:
{
type
:
Object
,
default
()
{
return
{
// 是否显示边框
border
:
true
,
// 是否显示分隔线
dividline
:
true
,
// 线条样式
borderStyle
:
{}
};
}
},
imageStyles
:
{
type
:
Object
,
default
()
{
return
{
width
:
'auto'
,
height
:
'auto'
};
}
},
readonly
:
{
type
:
Boolean
,
default
:
false
},
returnType
:
{
type
:
String
,
default
:
'array'
},
sizeType
:
{
type
:
Array
,
default
()
{
return
[
'original'
,
'compressed'
];
}
}
},
data
()
{
return
{
files
:
[],
localValue
:
[]
};
},
watch
:
{
// #ifndef VUE3
value
:
{
handler
(
newVal
,
oldVal
)
{
this
.
setValue
(
newVal
,
oldVal
);
},
immediate
:
true
},
// #endif
// #ifdef VUE3
modelValue
:
{
handler
(
newVal
,
oldVal
)
{
this
.
setValue
(
newVal
,
oldVal
);
},
immediate
:
true
}
// #endif
},
computed
:
{
filesList
()
{
let
files
=
[];
this
.
files
.
forEach
(
v
=>
{
files
.
push
(
v
);
});
return
files
;
},
showType
()
{
if
(
this
.
fileMediatype
===
'image'
)
{
return
this
.
mode
;
}
return
'list'
;
},
limitLength
()
{
if
(
this
.
returnType
===
'object'
)
{
return
1
;
}
if
(
!
this
.
limit
)
{
return
1
;
}
if
(
this
.
limit
>=
9
)
{
return
9
;
}
return
this
.
limit
;
}
},
created
()
{
// TODO 兼容不开通服务空间的情况
if
(
!
(
uniCloud
.
config
&&
uniCloud
.
config
.
provider
))
{
this
.
noSpace
=
true
;
uniCloud
.
chooseAndUploadFile
=
chooseAndUploadFile
;
}
this
.
form
=
this
.
getForm
(
'uniForms'
);
this
.
formItem
=
this
.
getForm
(
'uniFormsItem'
);
if
(
this
.
form
&&
this
.
formItem
)
{
if
(
this
.
formItem
.
name
)
{
this
.
rename
=
this
.
formItem
.
name
;
this
.
form
.
inputChildrens
.
push
(
this
);
}
}
},
methods
:
{
/**
* 公开用户使用,清空文件
* @param {Object} index
*/
clearFiles
(
index
)
{
if
(
index
!==
0
&&
!
index
)
{
this
.
files
=
[];
this
.
$nextTick
(()
=>
{
this
.
setEmit
();
});
}
else
{
this
.
files
.
splice
(
index
,
1
);
}
this
.
$nextTick
(()
=>
{
this
.
setEmit
();
});
},
/**
* 公开用户使用,继续上传
*/
upload
()
{
let
files
=
[];
this
.
files
.
forEach
((
v
,
index
)
=>
{
if
(
v
.
status
===
'ready'
||
v
.
status
===
'error'
)
{
files
.
push
(
Object
.
assign
({},
v
));
}
});
this
.
uploadFiles
(
files
);
},
async
setValue
(
newVal
,
oldVal
)
{
const
newData
=
async
v
=>
{
const
reg
=
/cloud:
\/\/([\w
.
]
+
\/?)\S
*/
;
let
url
=
''
;
if
(
v
.
fileID
)
{
url
=
v
.
fileID
;
}
else
{
url
=
v
.
url
;
}
if
(
reg
.
test
(
url
))
{
v
.
fileID
=
url
;
v
.
url
=
await
this
.
getTempFileURL
(
url
);
}
v
.
path
=
v
.
url
;
return
v
;
};
if
(
this
.
returnType
===
'object'
)
{
if
(
newVal
)
{
await
newData
(
newVal
);
}
else
{
newVal
=
{};
}
}
else
{
if
(
!
newVal
)
newVal
=
[];
for
(
let
i
=
0
;
i
<
newVal
.
length
;
i
++
)
{
let
v
=
newVal
[
i
];
await
newData
(
v
);
}
}
this
.
localValue
=
newVal
;
if
(
this
.
form
&&
this
.
formItem
&&
!
this
.
is_reset
)
{
this
.
is_reset
=
false
;
this
.
formItem
.
setValue
(
this
.
localValue
);
}
let
filesData
=
Object
.
keys
(
newVal
).
length
>
0
?
newVal
:
[];
this
.
files
=
[].
concat
(
filesData
);
},
/**
* 选择文件
*/
choose
()
{
if
(
this
.
disabled
)
return
;
if
(
this
.
files
.
length
>=
Number
(
this
.
limitLength
)
&&
this
.
showType
!==
'grid'
&&
this
.
returnType
===
'array'
)
{
uni
.
showToast
({
title
:
`您最多选择
${
this
.
limitLength
}
个文件`
,
icon
:
'none'
});
return
;
}
this
.
chooseFiles
();
},
/**
* 选择文件并上传
*/
chooseFiles
()
{
const
_extname
=
get_extname
(
this
.
fileExtname
);
// 获取后缀
uniCloud
.
chooseAndUploadFile
({
type
:
this
.
fileMediatype
,
compressed
:
false
,
sizeType
:
this
.
sizeType
,
// TODO 如果为空,video 有问题
extension
:
_extname
.
length
>
0
?
_extname
:
undefined
,
count
:
this
.
limitLength
-
this
.
files
.
length
,
//默认9
onChooseFile
:
this
.
chooseFileCallback
,
onUploadProgress
:
progressEvent
=>
{
this
.
setProgress
(
progressEvent
,
progressEvent
.
index
);
}
})
.
then
(
result
=>
{
this
.
setSuccessAndError
(
result
.
tempFiles
);
})
.
catch
(
err
=>
{
console
.
log
(
'选择失败'
,
err
);
});
},
/**
* 选择文件回调
* @param {Object} res
*/
async
chooseFileCallback
(
res
)
{
const
_extname
=
get_extname
(
this
.
fileExtname
);
const
is_one
=
(
Number
(
this
.
limitLength
)
===
1
&&
this
.
disablePreview
&&
!
this
.
disabled
)
||
this
.
returnType
===
'object'
;
// 如果这有一个文件 ,需要清空本地缓存数据
if
(
is_one
)
{
this
.
files
=
[];
}
let
{
filePaths
,
files
}
=
get_files_and_is_max
(
res
,
_extname
);
if
(
!
(
_extname
&&
_extname
.
length
>
0
))
{
filePaths
=
res
.
tempFilePaths
;
files
=
res
.
tempFiles
;
}
let
currentData
=
[];
for
(
let
i
=
0
;
i
<
files
.
length
;
i
++
)
{
if
(
this
.
limitLength
-
this
.
files
.
length
<=
0
)
break
;
files
[
i
].
uuid
=
Date
.
now
();
let
filedata
=
await
get_file_data
(
files
[
i
],
this
.
fileMediatype
);
filedata
.
progress
=
0
;
filedata
.
status
=
'ready'
;
this
.
files
.
push
(
filedata
);
currentData
.
push
({
...
filedata
,
file
:
files
[
i
]
});
}
this
.
$emit
(
'select'
,
{
tempFiles
:
currentData
,
tempFilePaths
:
filePaths
});
res
.
tempFiles
=
files
;
// 停止自动上传
if
(
!
this
.
autoUpload
||
this
.
noSpace
)
{
res
.
tempFiles
=
[];
}
},
/**
* 批传
* @param {Object} e
*/
uploadFiles
(
files
)
{
files
=
[].
concat
(
files
);
uploadCloudFiles
.
call
(
this
,
files
,
5
,
res
=>
{
this
.
setProgress
(
res
,
res
.
index
,
true
);
})
.
then
(
result
=>
{
this
.
setSuccessAndError
(
result
);
})
.
catch
(
err
=>
{
console
.
log
(
err
);
});
},
/**
* 成功或失败
*/
async
setSuccessAndError
(
res
,
fn
)
{
let
successData
=
[];
let
errorData
=
[];
let
tempFilePath
=
[];
let
errorTempFilePath
=
[];
for
(
let
i
=
0
;
i
<
res
.
length
;
i
++
)
{
const
item
=
res
[
i
];
const
index
=
item
.
uuid
?
this
.
files
.
findIndex
(
p
=>
p
.
uuid
===
item
.
uuid
)
:
item
.
index
;
if
(
index
===
-
1
||
!
this
.
files
)
break
;
if
(
item
.
errMsg
===
'request:fail'
)
{
this
.
files
[
index
].
url
=
item
.
path
;
this
.
files
[
index
].
status
=
'error'
;
this
.
files
[
index
].
errMsg
=
item
.
errMsg
;
// this.files[index].progress = -1
errorData
.
push
(
this
.
files
[
index
]);
errorTempFilePath
.
push
(
this
.
files
[
index
].
url
);
}
else
{
this
.
files
[
index
].
errMsg
=
''
;
this
.
files
[
index
].
fileID
=
item
.
url
;
const
reg
=
/cloud:
\/\/([\w
.
]
+
\/?)\S
*/
;
if
(
reg
.
test
(
item
.
url
))
{
this
.
files
[
index
].
url
=
await
this
.
getTempFileURL
(
item
.
url
);
}
else
{
this
.
files
[
index
].
url
=
item
.
url
;
}
this
.
files
[
index
].
status
=
'success'
;
this
.
files
[
index
].
progress
+=
1
;
successData
.
push
(
this
.
files
[
index
]);
tempFilePath
.
push
(
this
.
files
[
index
].
fileID
);
}
}
if
(
successData
.
length
>
0
)
{
this
.
setEmit
();
// 状态改变返回
this
.
$emit
(
'success'
,
{
tempFiles
:
this
.
backObject
(
successData
),
tempFilePaths
:
tempFilePath
});
}
if
(
errorData
.
length
>
0
)
{
this
.
$emit
(
'fail'
,
{
tempFiles
:
this
.
backObject
(
errorData
),
tempFilePaths
:
errorTempFilePath
});
}
},
/**
* 获取进度
* @param {Object} progressEvent
* @param {Object} index
* @param {Object} type
*/
setProgress
(
progressEvent
,
index
,
type
)
{
const
fileLenth
=
this
.
files
.
length
;
const
percentNum
=
(
index
/
fileLenth
)
*
100
;
const
percentCompleted
=
Math
.
round
((
progressEvent
.
loaded
*
100
)
/
progressEvent
.
total
);
let
idx
=
index
;
if
(
!
type
)
{
idx
=
this
.
files
.
findIndex
(
p
=>
p
.
uuid
===
progressEvent
.
tempFile
.
uuid
);
}
if
(
idx
===
-
1
||
!
this
.
files
[
idx
])
return
;
// fix by mehaotian 100 就会消失,-1 是为了让进度条消失
this
.
files
[
idx
].
progress
=
percentCompleted
-
1
;
// 上传中
this
.
$emit
(
'progress'
,
{
index
:
idx
,
progress
:
parseInt
(
percentCompleted
),
tempFile
:
this
.
files
[
idx
]
});
},
/**
* 删除文件
* @param {Object} index
*/
delFile
(
index
)
{
this
.
$emit
(
'delete'
,
{
tempFile
:
this
.
files
[
index
],
tempFilePath
:
this
.
files
[
index
].
url
});
this
.
files
.
splice
(
index
,
1
);
this
.
$nextTick
(()
=>
{
this
.
setEmit
();
});
},
/**
* 获取文件名和后缀
* @param {Object} name
*/
getFileExt
(
name
)
{
const
last_len
=
name
.
lastIndexOf
(
'.'
);
const
len
=
name
.
length
;
return
{
name
:
name
.
substring
(
0
,
last_len
),
ext
:
name
.
substring
(
last_len
+
1
,
len
)
};
},
/**
* 处理返回事件
*/
setEmit
()
{
let
data
=
[];
if
(
this
.
returnType
===
'object'
)
{
data
=
this
.
backObject
(
this
.
files
)[
0
];
this
.
localValue
=
data
?
data
:
null
;
}
else
{
data
=
this
.
backObject
(
this
.
files
);
if
(
!
this
.
localValue
)
{
this
.
localValue
=
[];
}
this
.
localValue
=
[...
data
];
}
// #ifdef VUE3
this
.
$emit
(
'update:modelValue'
,
this
.
localValue
);
// #endif
// #ifndef VUE3
this
.
$emit
(
'input'
,
this
.
localValue
);
// #endif
},
/**
* 处理返回参数
* @param {Object} files
*/
backObject
(
files
)
{
let
newFilesData
=
[];
files
.
forEach
(
v
=>
{
newFilesData
.
push
({
extname
:
v
.
extname
,
fileType
:
v
.
fileType
,
image
:
v
.
image
,
name
:
v
.
name
,
path
:
v
.
path
,
size
:
v
.
size
,
fileID
:
v
.
fileID
,
url
:
v
.
url
});
});
return
newFilesData
;
},
async
getTempFileURL
(
fileList
)
{
fileList
=
{
fileList
:
[].
concat
(
fileList
)
};
const
urls
=
await
uniCloud
.
getTempFileURL
(
fileList
);
return
urls
.
fileList
[
0
].
tempFileURL
||
''
;
},
/**
* 获取父元素实例
*/
getForm
(
name
=
'uniForms'
)
{
let
parent
=
this
.
$parent
;
let
parentName
=
parent
.
$options
.
name
;
while
(
parentName
!==
name
)
{
parent
=
parent
.
$parent
;
if
(
!
parent
)
return
false
;
parentName
=
parent
.
$options
.
name
;
}
return
parent
;
}
}
};
</
script
>
<
style
lang=
"scss"
>
.uni-file-picker
{
/* #ifndef APP-NVUE */
box-sizing
:
border-box
;
overflow
:
hidden
;
/* #endif */
}
.uni-file-picker__header
{
padding-top
:
5px
;
padding-bottom
:
10px
;
/* #ifndef APP-NVUE */
display
:
flex
;
/* #endif */
justify-content
:
space-between
;
}
.file-title
{
font-size
:
14px
;
color
:
#333
;
}
.file-count
{
font-size
:
14px
;
color
:
#999
;
}
.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
);
}
.add-wrap
{
width
:
200rpx
;
height
:
200rpx
;
border-radius
:
10rpx
;
background-color
:
#F5F5F5
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
center
;
align-items
:
center
;
text
{
font-size
:
20rpx
;
color
:
#616161
;
margin-top
:
10rpx
;
}
}
</
style
>
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
...
...
@@ -7,6 +7,10 @@ import {
alert
}
from
'../utils/fun.js'
;
import
{
apiPOST
}
from
'../common/utils/apiRequest.js'
const
app
=
getApp
();
export
default
{
...
...
@@ -34,10 +38,10 @@ export default {
}
},
methods
:
{
authTo
(
url
)
{
//登录校验
authTo
(
url
)
{
//登录校验
},
authToNs
(
url
)
{
//登录校验不保留当前页面
authToNs
(
url
)
{
//登录校验不保留当前页面
},
loadData
()
{},
...
...
@@ -78,14 +82,6 @@ export default {
logout
()
{
uni
.
removeStorageSync
(
'token'
);
},
put
(
options
)
{
options
=
Object
.
assign
({
showLoading
:
true
},
options
,
{
method
:
'PUT'
})
this
.
req
(
options
);
},
post
(
options
)
{
options
=
Object
.
assign
({
showLoading
:
true
...
...
@@ -94,14 +90,14 @@ export default {
})
this
.
req
(
options
);
},
get
(
options
)
{
options
=
Object
.
assign
({
showLoading
:
false
},
options
,
{
method
:
'GET'
})
this
.
req
(
options
);
},
// get(options) {
// options = Object.assign({
// showLoading: false
// }, options, {
// method: 'GET'
// })
// this.req(options);
// },
req
(
options
)
{
let
{
showLoading
,
...
...
@@ -116,60 +112,22 @@ export default {
showLoading
&&
loading
.
show
();
let
requestTask
;
let
uniChannel
=
'wechat'
;
// #ifdef MP-KUAISHOU
uniChannel
=
'kuaishou'
;
// #endif
// #ifdef MP-TOUTIAO
uniChannel
=
'douyin'
;
// #endif
apiPOST
({
url
:
`
${
url
}
`
,
data
:
data
,
callback
:
(
_success
,
_data
)
=>
{
showLoading
&&
loading
.
hide
();
Object
.
assign
(
header
,
{
token
:
uni
.
getStorageSync
(
'token'
),
pkgName
:
app
.
globalData
.
pkgName
,
proChannel
:
uniChannel
if
(
_success
)
{
success
({
data
:
_data
})
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
);
}
}
else
{
fail
(
_data
)
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
)
}
}
};
\ No newline at end of file
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
<
template
>
<view>
<uni-list>
<!--
<uni-list-item
:thumb=
"editParam.avater"
thumbSize=
'lg'
rightText=
'上传头像'
:showArrow=
'true'
:clickable=
'true'
@
click=
"uploadAction"
></uni-list-item>
-->
<uni-list-item
title=
"昵称"
:rightText=
"editParam.nickName"
:showArrow=
'true'
:clickable=
'true'
@
click=
"inputAction('nickName')"
></uni-list-item>
<uni-list-item
title=
"性别"
:showArrow=
'true'
>
<template
v-slot:footer
>
<picker
:range=
"sexRange"
range-key=
"label"
:value=
'sexValue.index'
@
change=
'pickerAction( $event, "sex")'
>
<view
class=
"sex"
>
{{
sexValue
.
name
}}
</view>
</picker>
</
template
>
</uni-list-item>
<uni-list-item
title=
"签名"
:rightText=
"editParam.sign"
:showArrow=
'true'
:clickable=
'true'
@
click=
"inputAction('sign')"
></uni-list-item>
<uni-list-item
direction=
"column"
:clickable=
'false'
>
<
template
v-slot:body
>
<view
class=
"button-box"
>
<button
class=
"c-button_clear c-button-size_lg c-button-width_full confirm"
:disabled=
"loading"
:loading=
'loading'
@
click
.
stop=
'confirm'
>
提交修改信息
</button>
</view>
</
template
>
</uni-list-item>
</uni-list>
<edit-input-pop
:show=
'showInputPop'
:type=
'inputType'
:value=
'inputValue'
:placeholder=
'inputPlaceholder'
@
close=
'closeInputPop'
@
changeValue=
'changeInputValue'
></edit-input-pop>
<c-login></c-login>
</view>
</template>
<
script
>
import
EditInputPop
from
"./components/edit-input-pop.vue"
;
import
{
getSexDict
,
editUserInfo
,
uploadAvater
}
from
"./services/index.js"
;
import
Validator
from
"../../../common/utils/validator.js"
import
{
toastMessage
}
from
"../../../common/utils/toastUtil"
;
import
{
refreshUserInfo
}
from
"../../../common/services/userServices.js"
export
default
{
components
:
{
EditInputPop
},
data
()
{
return
{
editParam
:
null
,
showInputPop
:
false
,
inputType
:
""
,
inputValue
:
""
,
inputPlaceholder
:
""
,
loading
:
false
,
sexRange
:
[],
};
},
computed
:
{
sexValue
:
function
()
{
let
result
=
{
index
:
-
1
,
name
:
'保密'
}
if
(
this
.
editParam
&&
this
.
sexRange
)
{
this
.
sexRange
.
forEach
((
item
,
index
)
=>
{
if
(
item
.
value
==
this
.
editParam
.
sex
)
{
result
=
{
index
,
name
:
item
.
label
}
}
})
}
return
result
;
},
},
onLoad
()
{
const
eventChannel
=
this
.
getOpenerEventChannel
();
eventChannel
.
on
(
"openUserEditPage"
,
(
info
)
=>
{
this
.
editParam
=
info
.
userInfo
?
{
...
info
.
userInfo
}
:
{};
})
this
.
getSexRange
();
},
methods
:
{
getSexRange
()
{
getSexDict
((
success
,
data
)
=>
{
if
(
success
)
{
this
.
sexRange
=
data
.
sort
((
a
,
b
)
=>
{
return
a
.
sort
-
b
.
sort
});
}
})
},
uploadAction
()
{
let
chooseImageFn
=
(
callback
)
=>
{
uni
.
chooseImage
({
count
:
1
,
success
:
(
res
)
=>
{
if
(
typeof
callback
==
'function'
)
callback
(
res
.
tempFilePaths
[
0
])
}
})
}
let
uploadFn
=
(
filePath
)
=>
{
uploadAvater
(
filePath
,
(
success
,
data
)
=>
{
if
(
success
)
{
this
.
$set
(
this
.
editParam
,
'avater'
,
data
);
}
})
}
chooseImageFn
((
filePath
)
=>
{
uploadFn
(
filePath
)
})
},
pickerAction
(
e
,
type
)
{
let
index
=
Number
(
e
.
detail
.
value
)
if
(
type
==
'sex'
)
{
this
.
$set
(
this
.
editParam
,
type
,
this
.
sexRange
[
index
].
value
);
}
},
inputAction
(
type
)
{
let
s
=
{
"nickName"
:
{
value
:
this
.
editParam
.
nickName
,
placeholder
:
"请输入昵称"
,
maxLegnth
:
20
,
},
"sign"
:
{
value
:
this
.
editParam
.
sign
,
placeholder
:
"请输入签名"
,
maxLegnth
:
40
,
}
}
this
.
showEditInputPop
(
type
,
s
[
type
].
value
,
s
[
type
].
placeholder
,
s
[
type
].
maxLength
)
},
showEditInputPop
(
type
,
value
,
placeholder
,
maxLength
)
{
this
.
inputType
=
type
;
this
.
inputValue
=
value
;
this
.
inputPlaceholder
=
placeholder
;
this
.
maxLength
=
maxLength
;
this
.
showInputPop
=
true
;
},
closeInputPop
()
{
this
.
showInputPop
=
false
;
},
changeInputValue
(
e
)
{
let
value
=
e
.
detail
.
value
;
let
type
=
e
.
detail
.
type
;
this
.
$set
(
this
.
editParam
,
type
,
value
);
},
confirm
()
{
if
(
this
.
loading
)
return
;
let
validator
=
new
Validator
();
validator
.
add
(
this
.
editParam
.
id
,
"isNotEmpty"
,
"错误的id"
);
validator
.
add
(
this
.
editParam
.
nickName
,
"isNotEmpty"
,
"昵称不能为空"
);
let
errMsg
=
validator
.
start
();
if
(
errMsg
)
{
toastMessage
(
errMsg
);
return
;
}
this
.
loading
=
true
;
editUserInfo
(
this
.
editParam
,
(
success
,
data
)
=>
{
this
.
loading
=
false
;
if
(
success
)
{
toastMessage
(
'修改成功'
)
refreshUserInfo
();
}
})
}
}
}
</
script
>
<
style
lang=
"scss"
>
.button-box
{
display
:
flex
;
flex-direction
:
row
;
align-items
:
center
;
justify-content
:
space-around
;
.confirm
{
background
:
#FECF02
;
color
:
#333
;
}
}
.sex
{
font-size
:
24rpx
;
color
:
#999
;
width
:
200rpx
;
height
:
50rpx
;
line-height
:
50rpx
;
text-align
:
right
;
}
</
style
>
\ No newline at end of file
vedio/page-subs/sub_B/vip-apply/vip-apply.vue
deleted
100644 → 0
View file @
abb53a01
<
template
>
<view
class=
"view-box"
>
<image
class=
"header"
:style=
"[headerStyle]"
src=
"/static/images/vip-apply/header.png"
mode=
"scaleToFill"
>
</image>
<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>
<c-login></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
SystemInfoMixin
from
"../../../common/mixins/system-info-mixin.js"
;
import
Pack
from
"../../../common/models/Pack.js"
;
import
{
getPackData
,
getOpenId
,
getPayInfoDy
}
from
"../../../common/services/index.js"
;
import
PayInfo
from
"../../../common/models/PayInfo.js"
import
{
watchUserInfoChange
,
removeUserInfoChangeWatch
,
showLoginView
,
refreshUserInfo
,
postPhone
}
from
"../../../common/services/userServices.js"
import
{
toastMessage
}
from
"../../../common/utils/toastUtil.js"
;
import
User
from
"../../../common/models/User.js"
import
{
saveStorage
,
readStorage
}
from
"../../../common/utils/storageUtil.js"
;
export
default
{
mixins
:
[
SystemInfoMixin
],
data
()
{
return
{
packList
:
[],
selectedIndex
:
0
,
loading
:
false
,
os
:
'android'
,
userInfo
:
null
,
showMoibleLogin
:
false
,
mobileLoginLock
:
false
,
};
},
onLoad
()
{
if
(
tt
.
getSystemInfoSync
().
platform
===
'ios'
)
{
this
.
os
=
'ios'
;
}
this
.
refrehsPackData
();
this
.
mobileLoginLock
=
readStorage
(
"KEY_NEED_PHONE"
)
},
onReady
()
{
watchUserInfoChange
((
info
)
=>
{
this
.
userInfo
=
info
.
userInfo
;
},
this
)
},
onUnload
()
{
removeUserInfoChangeWatch
(
this
);
},
computed
:
{
headerStyle
:
function
()
{
return
{
width
:
`
${
this
.
windowWidth
}
px`
,
height
:
`
${
this
.
windowWidth
*
0.61
}
px`
}
}
},
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
.
id
,
code
:
e
.
detail
.
code
,
}
postPhone
(
params
,
(
success
,
result
)
=>
{
if
(
success
)
{
saveStorage
(
"KEY_NEED_PHONE"
,
false
);
this
.
mobileLoginLock
=
false
this
.
tapPay
()
}
else
{
uni
.
showModal
({
title
:
"提示"
,
content
:
"网络错误!"
})
}
})
},
refrehsPackData
()
{
// getPackData((success, data) => {
// this.packList = data.map(item => {
// return new Pack(item);
// })
// })
},
choosePack
(
item
,
index
)
{
this
.
selectedIndex
=
index
;
},
tapPay
()
{
let
that
=
this
;
let
vipBean
=
this
.
packList
[
this
.
selectedIndex
];
getPayInfoDy
(
vipBean
.
pid
,
(
success
,
data
)
=>
{
if
(
success
)
{
that
.
ttPrePay
(
data
);
}
})
},
ttPrePay
(
ttData
)
{
if
(
!
tt
.
canIUse
(
'requestOrder'
))
{
toastMessage
(
'请升级抖音APP版本!'
);
return
}
let
that
=
this
;
tt
.
requestOrder
({
data
:
ttData
.
params
.
data
,
byteAuthorization
:
ttData
.
params
.
byteAuthorization
,
success
(
res
)
{
that
.
ttPay
(
res
.
orderId
,
ttData
);
},
fail
(
res
)
{
toastMessage
(
res
.
errMsg
);
console
.
log
(
'requestOrder res.errMsg'
,
res
)
},
});
},
ttPay
(
oid
,
ttData
)
{
if
(
!
tt
.
canIUse
(
'getOrderPayment'
))
{
toastMessage
(
'请升级抖音APP版本~'
);
return
}
if
(
this
.
os
==
'ios'
)
{
if
(
!
tt
.
canIUse
(
'getOrderPayment.object.imId'
))
{
toastMessage
(
'请升级抖音APP版本.'
);
return
}
tt
.
getOrderPayment
({
orderId
:
oid
,
imId
:
ttData
.
imId
,
success
(
res
)
{
toastMessage
(
'会员购买成功'
)
refreshUserInfo
();
},
fail
(
res
)
{
console
.
log
(
'ios=ttPay res.errMsg'
,
res
)
},
});
}
else
{
tt
.
getOrderPayment
({
orderId
:
oid
,
success
(
res
)
{
toastMessage
(
'会员购买成功'
)
refreshUserInfo
();
},
fail
(
res
)
{
console
.
log
(
'android=ttPay res.errMsg'
,
res
)
},
});
}
}
}
}
</
script
>
<
style
lang=
"scss"
>
.view-box
{
display
:
flex
;
flex-direction
:
column
;
position
:
relative
;
.header
{
width
:
100%
;
}
.section
{
padding
:
0
30rpx
;
display
:
flex
;
flex-direction
:
column
;
background
:
#fff
;
.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
:
#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/pages.json
View file @
dbf68494
...
...
@@ -76,52 +76,6 @@
"enablePullDownRefresh"
:
false
}
},
{
"path"
:
"read-history/read-history"
,
"style"
:
{
"navigationBarTitleText"
:
"阅读记录"
,
"enablePullDownRefresh"
:
false
}
}]
},
{
"root"
:
"page-subs/sub_B"
,
"pages"
:
[{
"path"
:
"user-edit/user-edit"
,
"style"
:
{
"navigationBarTitleText"
:
"用户编辑"
,
"enablePullDownRefresh"
:
false
}
},
{
"path"
:
"message/message"
,
"style"
:
{
"navigationBarTitleText"
:
"系统消息"
,
"enablePullDownRefresh"
:
false
}
},
{
"path"
:
"read-preference/read-preference"
,
"style"
:
{
"navigationBarTitleText"
:
"阅读喜好"
,
"enablePullDownRefresh"
:
false
}
},
{
"path"
:
"book-bean-detail/book-bean-detail"
,
"style"
:
{
"navigationBarTitleText"
:
"书豆明细"
,
"enablePullDownRefresh"
:
false
}
},
{
"path"
:
"feedback/feedback"
,
"style"
:
{
"navigationBarTitleText"
:
"问题反馈"
,
"enablePullDownRefresh"
:
false
}
},
{
"path"
:
"book-bean-recharge/book-bean-recharge"
,
"style"
:
{
"navigationBarTitleText"
:
"书豆充值"
,
"enablePullDownRefresh"
:
true
}
}]
},
{
"root"
:
"pagesD"
,
...
...
@@ -164,7 +118,7 @@
//
当我们进入了pages/home页面以后就会预下载pagesA分包
"pages/home"
:
{
"network"
:
"all"
,
//在指定网络下预下载,可选值为:all(不限网络)、wifi(仅wifi下预下载)
"packages"
:
[
"pagesA"
,
"page-subs/sub_A"
,
"page
-subs/sub_B"
,
"page
sD"
]
//进入页面后预下载分包
"packages"
:
[
"pagesA"
,
"page-subs/sub_A"
,
"pagesD"
]
//进入页面后预下载分包
}
},
"globalStyle"
:
{
...
...
vedio/pages/loading.vue
View file @
dbf68494
...
...
@@ -18,6 +18,10 @@
</
template
>
<
script
>
import
{
saveToken
}
from
'../common/services/userServices.js'
import
{
message
,
redirectTo
,
...
...
@@ -85,10 +89,7 @@
data
})
=>
{
app
.
globalData
.
userId
=
data
.
idcode
;
uni
.
setStorage
({
key
:
'token'
,
data
:
data
.
token
});
saveToken
(
data
.
token
)
setTimeout
(()
=>
{
redirectTo
(
'home'
);
},
1000
);
...
...
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