Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
P
project-online-fi
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
project-online-fi
Commits
2daf00e0
提交
2daf00e0
authored
11月 25, 2022
作者:
matian
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
updates
上级
509e6f92
隐藏空白字符变更
内嵌
并排
正在显示
11 个修改的文件
包含
1204 行增加
和
875 行删除
+1204
-875
Confirm.vue
src/modules/pay/components/Confirm.vue
+0
-731
PayH5.vue
src/modules/pay/components/PayH5.vue
+375
-0
PayPC.vue
src/modules/pay/components/PayPC.vue
+505
-0
usePay.ts
src/modules/pay/composables/usePay.ts
+123
-0
index.ts
src/modules/pay/index.ts
+14
-1
type.ts
src/modules/pay/type.ts
+38
-0
Index.vue
src/modules/pay/views/Index.vue
+16
-48
Order.vue
src/modules/pay/views/Order.vue
+102
-84
index.ts
src/router/index.ts
+16
-6
user.ts
src/stores/user.ts
+5
-5
index.ts
src/utils/index.ts
+10
-0
没有找到文件。
src/modules/pay/components/Confirm.vue
deleted
100644 → 0
浏览文件 @
509e6f92
<
script
setup
lang=
"ts"
>
import
{
ElMessage
}
from
'element-plus'
import
{
Check
}
from
'@element-plus/icons-vue'
import
{
useUserStore
}
from
'@/stores/user'
import
{
useDevice
}
from
'@/composables/useDevice'
import
{
wxJSPay
,
getOpenId
}
from
'@/utils/wxpay'
import
{
createOrder
,
getOrderList
}
from
'../api'
import
queryString
from
'query-string'
const
router
=
useRouter
()
const
{
mobile
,
wechat
,
alipay
}
=
useDevice
()
const
user
=
useUserStore
()
const
props
=
defineProps
({
shopItem
:
{
type
:
Object
}
})
const
dialogVisible
=
ref
(
false
)
const
item
=
ref
({
url
:
'https://webapp-pub.oss-cn-beijing.aliyuncs.com/center_resource/%E7%B4%AB%E8%8D%86%E6%95%99%E8%82%B2%E7%94%A8%E6%88%B7%E5%85%A5%E9%A9%BB%E5%8F%8A%E7%BD%91%E7%BB%9C%E6%95%99%E5%AD%A6%E8%B5%84%E6%BA%90%E5%8D%8F%E8%AE%AE(1).docx'
})
const
orderInfo
:
any
=
ref
({})
const
payMode
=
ref
(
1
)
const
isAgree
=
ref
(
false
)
const
isAgreeText
=
ref
(
false
)
const
currentCheck
=
ref
(
'4'
)
const
orderInfoDetail
:
any
=
ref
([])
function
getDateTime
(
dayNum
:
any
)
{
const
dateDay
=
new
Date
()
dateDay
.
setDate
(
dateDay
.
getDate
()
+
dayNum
)
//获取dayNum天后的日期
console
.
log
(
dateDay
)
const
y
=
dateDay
.
getFullYear
()
const
m
=
dateDay
.
getMonth
()
+
1
<
10
?
'0'
+
(
dateDay
.
getMonth
()
+
1
)
:
dateDay
.
getMonth
()
+
1
//获取当前月份的日期,不足10补0
const
d
=
dateDay
.
getDate
()
<
10
?
'0'
+
dateDay
.
getDate
()
:
dateDay
.
getDate
()
//获取当前几号,不足10补0
return
y
+
'-'
+
m
+
'-'
+
d
}
const
start_time
=
getDateTime
(
0
)
const
end_time
=
getDateTime
(
90
)
const
emit
=
defineEmits
<
{
(
e
:
'success'
,
params
:
object
):
void
}
>
()
const
checkdChange
=
(
val
:
string
)
=>
{
currentCheck
.
value
=
val
}
const
optionParams
=
reactive
({
shop_id
:
'6998523899570814976'
,
spu_id
:
'6998525810348916736'
,
sku_id
:
'6998525810365693952'
,
redirect_url
:
''
,
buy_count
:
'1'
,
payment_method
:
''
,
notify_url
:
`https://ep-lms-api.ezijing.com/v2/student/push?tenant=paa&sso_id=
${
user
.
user
?.
id
}
&
class_id
=
$
{
props
.
shopItem
?.
class_id
}
&
course_flag
=
1
&
course_id
=
$
{
props
.
shopItem
?.
course_id
}
`
})
// 点击立即购买
const handlePay = () => {
if (isAgree.value === false) {
ElMessage.warning('请先勾选紫荆金保服务协议')
isAgreeText.value = true
} else {
if (user.isLogin) {
if (!mobile.value) {
//pc
const params = {
payMode: payMode.value,
status: 'order'
}
emit('success', params)
} else {
//H5
if (mobile && (wechat || alipay)) {
pay()
}
}
} else {
window.location.href = `
$
{
import
.
meta
.
env
.
VITE_LOGIN_URL
}?
rd
=
$
{
encodeURIComponent
(
location
.
href
)}
`
}
}
}
// 去支付
const pay = () => {
console.log('999')
createOrderHandle().then((order: any) => {
orderInfo.value = order
if (wechat) {
wxJSPay(order, payCallback(optionParams))
} else {
location.href = order.payment_url // '4' \ '12'
getOrder()
}
})
}
// 支付回调
const payCallback = async (options: any) => {
const { callback } = options
const order = await getOrder()
callback && callback(order)
const params = {
status: 'success',
orderId: order.order_id,
payPrice: order.payment_money,
payStatus: order.order_status
}
orderInfoDetail.value = order.order_status
emit('success', params)
}
// 创建订单
const createOrderHandle = () => {
let defaultParams = {}
// 微信内
if (wechat) {
const openId = localStorage.getItem('openId')
if (!openId) {
getOpenId(
queryString.parse(location.search, { parseBooleans: true }).code,
pay
)
return Promise.reject('openId不存在')
}
defaultParams = { open_id: openId, payment_method: '3' }
}
// 支付宝网页支付
if (currentCheck.value === '12') {
defaultParams = { payment_method: '12' }
}
//微信外微信h5支付
if (currentCheck.value === '4') {
defaultParams = { payment_method: '4' }
}
const params = Object.assign(optionParams, defaultParams)
return createOrder(params).then((resp: any) => resp.data)
}
// 获取订单
function getOrder() {
return getOrderList({
order_detail_id: orderInfo.value.order_detail_id
}).then((resp) => {
return resp.data[0]
})
}
const handlePrev = () => {
router.push({
path: `
/
shop
/
detail
/
$
{
props
.
shopItem
?.
id
}
`,
query: {
payStatus: orderInfoDetail.value.order_status
}
})
}
const changeProtocol = () => {
dialogVisible.value = false
isAgree.value = true
isAgreeText.value = false
}
const handleAgree = (val: any) => {
isAgree.value = val
if (val === true) {
isAgreeText.value = false
}
}
</
script
>
<
template
>
<div>
<div
class=
"main_con"
v-if=
"!mobile"
>
<div
class=
"con_tit"
>
课程信息确认
</div>
<div
class=
"con_pay"
>
<div
class=
"pay_course"
>
<img
:src=
"
shopItem?.image_url ||
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fb%2F56e7995e3501f.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671671981&t=0eb627c761e6567a3a0a29163b31aac0'
"
alt=
""
/>
<div
class=
"course_info"
>
<div
class=
"info_tit"
>
{{
shopItem
?.
title
}}
</div>
<div
class=
"info_range"
>
有效期:
{{
start_time
}}
至
{{
end_time
}}
</div>
<div
class=
"info_price"
>
<div
class=
"price_icon"
>
¥
</div>
<div
class=
"price_num"
>
{{
shopItem
?.
price
}}
</div>
</div>
</div>
</div>
<div
class=
"con_message"
v-if=
"user.isLogin"
>
课程提醒将发送到您的手机:
{{
user
?.
mobile
}}
</div>
<div
class=
"con_mode"
>
<div
class=
"mode_tit"
>
支付方式
</div>
<div
class=
"mode_radio"
>
<el-radio-group
v-model=
"payMode"
>
<el-radio
:label=
"1"
size=
"large"
border
>
<img
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/pay_ali.png"
/>
<span
class=
"radio_tit"
>
支付宝支付
</span>
</el-radio>
<el-radio
:label=
"2"
size=
"large"
border
>
<img
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/pay_wechat.png"
/>
<span
class=
"radio_tit"
>
微信支付
</span>
</el-radio>
</el-radio-group>
</div>
</div>
<div
class=
"con_footer"
>
<div
class=
"footer_left"
>
<div
class=
"left_top"
>
<el-checkbox
v-model=
"isAgree"
@
change=
"handleAgree"
>
<span>
同意
</span></el-checkbox
><a
@
click=
"dialogVisible = true"
>
紫荆金保服务协议
</a>
</div>
<div
class=
"left_desc"
:class=
"isAgreeText === true ? 'left_desc_active' : ''"
>
请先勾选紫荆金保服务协议
</div>
</div>
<div
class=
"footer_right"
>
<div
class=
"right_top"
>
<div
class=
"top_tit"
>
需付金额:
</div>
<div
class=
"top_price"
>
<div
class=
"price_icon"
>
¥
</div>
<div
class=
"price_num"
>
{{
shopItem
?.
price
}}
</div>
</div>
</div>
<div
class=
"right_btn"
@
click=
"handlePay"
>
立即支付
</div>
</div>
</div>
</div>
</div>
<div
class=
"main_con"
v-else
>
<div
class=
"con_nav"
@
click=
"handlePrev"
>
<img
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/prev_mini.png"
/>
<div
class=
"nav_title"
>
确认订单
</div>
</div>
<div
class=
"course_con"
>
<img
:src=
"
shopItem?.image_url ||
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fb%2F56e7995e3501f.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671671981&t=0eb627c761e6567a3a0a29163b31aac0'
"
alt=
""
/>
<div
class=
"course_dec"
>
<div
class=
"info_title"
>
{{
shopItem
?.
title
}}
</div>
<div
class=
"info_date"
>
有效期:
{{
start_time
}}
至
{{
end_time
}}
</div>
</div>
</div>
<div
class=
"pay_con"
>
<div
class=
"pay_phone"
v-if=
"user?.isLogin"
>
课程提醒将发送到您的手机:
<i
style=
"font-weight: bold"
>
{{
user
?.
mobile
}}
</i>
</div>
<div
class=
"pay_line"
></div>
<div
class=
"pay_mode"
>
<div
class=
"mode_item"
>
<img
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/pay_ali.png"
/>
<div
class=
"radio_tit"
>
支付宝支付
</div>
<div
:class=
"
currentCheck === '12' ? 'radio_check_active' : 'radio_check'
"
@
click=
"checkdChange('12')"
>
<template
v-if=
"currentCheck === '12'"
>
<el-icon><Check
/></el-icon>
</
template
>
</div>
</div>
<div
class=
"mode_item"
>
<img
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/pay_wechat.png"
/>
<div
class=
"radio_tit"
>
微信支付
</div>
<div
:class=
"
currentCheck === '4' ? 'radio_check_active' : 'radio_check'
"
@
click=
"checkdChange('4')"
>
<
template
v-if=
"currentCheck === '4'"
>
<el-icon><Check
/></el-icon>
</
template
>
</div>
</div>
</div>
</div>
<div
class=
"argreement_con"
>
<div
class=
"left_top"
>
<el-checkbox
v-model=
"isAgree"
@
change=
"handleAgree"
>
<span>
同意
</span>
</el-checkbox>
<a
@
click=
"dialogVisible = true"
>
紫荆金保服务协议
</a>
</div>
<div
class=
"left_desc"
:class=
"isAgreeText === true ? 'left_desc_active' : ''"
>
请先勾选紫荆金保服务协议
</div>
</div>
<div
class=
"to_pay_main"
@
click=
"handlePay"
>
<div
class=
"pay_price"
>
<span
class=
"to_pay"
>
立即支付
</span>
<span
class=
"to_price"
><i
style=
"font-size: 12px"
>
¥
</i>
1999.00
</span>
</div>
</div>
</div>
<el-dialog
v-model=
"dialogVisible"
:width=
"!mobile ? '50%' : '90%'"
>
<div
style=
"height: 600px"
v-if=
"!mobile"
>
<iframe
:src=
"`https://view.officeapps.live.com/op/view.aspx?src=${item?.url}`"
frameborder=
"0"
width=
"100%"
height=
"100%"
></iframe>
</div>
<div
v-else
style=
"height: 8rem"
>
<iframe
:src=
"`https://view.xdocin.com/xdoc?_xdoc=${item?.url}`"
frameborder=
"0"
width=
"100%"
height=
"100%"
></iframe>
</div>
<
template
#
footer
>
<el-button
type=
"primary"
@
click=
"changeProtocol"
style=
"background-color: #e3a232; border: none"
>
我已阅读并同意
</el-button
>
</
template
>
</el-dialog>
</div>
</template>
<
style
lang=
"scss"
scoped
>
.is-h5
{
.main_con
{
padding
:
0
0
.28rem
;
.con_nav
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
position
:
relative
;
img
{
position
:
absolute
;
left
:
0
;
}
.nav_title
{
font-size
:
0
.32rem
;
font-weight
:
500
;
line-height
:
0
.34rem
;
color
:
#333333
;
}
}
.course_con
{
margin
:
0
.3rem
0
;
height
:
1
.97rem
;
background
:
#ffffff
;
opacity
:
1
;
border-radius
:
0
.12rem
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
padding
:
0
.28rem
0
.2rem
;
box-sizing
:
border-box
;
gap
:
0
.2rem
;
img
{
width
:
2
.2rem
;
height
:
1
.4rem
;
}
.course_dec
{
display
:
flex
;
flex-direction
:
column
;
gap
:
0
.2rem
;
.info_title
{
height
:
0
.64rem
;
font-size
:
0
.28rem
;
font-weight
:
500
;
line-height
:
0
.36rem
;
color
:
#333333
;
}
.info_date
{
font-size
:
0
.22rem
;
font-weight
:
400
;
line-height
:
0
.3rem
;
color
:
#999999
;
white-space
:
nowrap
;
}
}
}
.pay_con
{
width
:
6
.9rem
;
box-sizing
:
border-box
;
margin-bottom
:
0
.53rem
;
background
:
#fff
;
border-radius
:
0
.12rem
;
padding
:
0
.54rem
0
.4rem
;
.pay_phone
{
text-align
:
center
;
font-size
:
0
.24rem
;
color
:
#333333
;
}
.pay_line
{
height
:
0px
;
border
:
1px
solid
#f8f8f8
;
opacity
:
1
;
margin
:
0
.57rem
0
0
.54rem
0
;
}
.pay_mode
{
display
:
flex
;
flex-direction
:
column
;
gap
:
0
.4rem
;
.mode_item
{
display
:
flex
;
align-items
:
center
;
position
:
relative
;
img
{
width
:
0
.3rem
;
height
:
0
.3rem
;
}
.radio_tit
{
margin-left
:
0
.2rem
;
}
.radio_check_active
{
position
:
absolute
;
right
:
0
;
width
:
0
.25rem
;
height
:
0
.25rem
;
border-radius
:
50%
;
display
:
flex
;
align-items
:
center
;
font-size
:
12px
;
color
:
#fff
;
background-color
:
#f1b44e
;
box-sizing
:
border-box
;
}
.radio_check
{
position
:
absolute
;
right
:
0
;
width
:
0
.25rem
;
height
:
0
.25rem
;
border
:
1px
solid
#707070
;
border-radius
:
50%
;
display
:
flex
;
align-items
:
center
;
font-size
:
12px
;
color
:
#fff
;
box-sizing
:
border-box
;
}
}
}
}
.argreement_con
{
text-align
:
center
;
.left_top
{
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
.el-checkbox__label
{
span
{
color
:
#666666
;
font-size
:
0
.24rem
;
font-weight
:
400
;
}
}
a
{
font-weight
:
400
;
font-size
:
0
.24rem
;
color
:
#e3a232
!
important
;
margin-top
:
0
.02rem
;
cursor
:
pointer
;
}
}
.left_desc
{
color
:
#999999
;
font-size
:
0
.24rem
;
margin-left
:
0
.9rem
;
}
.left_desc_active
{
color
:
#aa1941
;
}
}
.to_pay_main
{
margin
:
3
.5rem
-0
.3rem
0
;
height
:
1
.2rem
;
background
:
#fff
;
opacity
:
1
;
border-radius
:
0
.2rem
0
.2rem
0px
0px
;
padding
:
0
.24rem
0
.3rem
0
.16rem
0
.3rem
;
box-sizing
:
border-box
;
.pay_price
{
width
:
100%
;
height
:
0
.8rem
;
background
:
linear-gradient
(
102deg
,
#f2ca8c
0%
,
#e69b1c
100%
);
border-radius
:
0
.4rem
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
color
:
#fff
;
gap
:
0
.18rem
;
.to_pay
{
font-size
:
0
.28rem
;
}
.to_price
{
font-size
:
0
.4rem
;
}
}
}
}
}
.is-pc
{
.main_con
{
width
:
1200px
;
margin
:
auto
;
.con_tit
{
font-size
:
28px
;
font-weight
:
500
;
line-height
:
34px
;
color
:
#333333
;
padding-top
:
39px
;
}
.con_pay
{
height
:
721px
;
background
:
#ffffff
;
margin-top
:
26px
;
padding
:
52px
60px
107px
40px
;
box-sizing
:
border-box
;
.pay_course
{
display
:
flex
;
padding-bottom
:
41px
;
border-bottom
:
1px
solid
#e6e6e6
;
img
{
width
:
257px
;
height
:
166px
;
}
.course_info
{
margin-left
:
35px
;
.info_tit
{
font-size
:
24px
;
font-weight
:
500
;
line-height
:
34px
;
color
:
#333333
;
}
.info_range
{
font-size
:
14px
;
font-weight
:
400
;
line-height
:
34px
;
color
:
#666666
;
margin-top
:
26px
;
}
.info_price
{
display
:
flex
;
align-items
:
flex-end
;
margin-top
:
42px
;
.price_icon
{
font-size
:
20px
;
font-weight
:
500
;
color
:
#aa1941
;
}
.price_num
{
font-size
:
30px
;
font-weight
:
normal
;
line-height
:
34px
;
color
:
#aa1941
;
}
}
}
}
}
.con_message
{
margin-top
:
30px
;
font-size
:
18px
;
font-weight
:
500
;
line-height
:
34px
;
color
:
#333333
;
}
.con_mode
{
margin-top
:
43px
;
display
:
flex
;
align-items
:
center
;
.mode_tit
{
font-size
:
16px
;
font-weight
:
400
;
line-height
:
34px
;
color
:
#333333
;
}
.mode_radio
{
margin-left
:
44px
;
}
}
.con_footer
{
margin-top
:
74px
;
display
:
flex
;
justify-content
:
space-between
;
.footer_left
{
padding-top
:
12px
;
.left_top
{
display
:
flex
;
align-items
:
center
;
.el-checkbox__label
{
span
{
color
:
#666666
;
font-size
:
16px
;
font-weight
:
400
;
}
}
a
{
color
:
#e3a232
;
font-size
:
16px
;
font-weight
:
400
;
margin-top
:
-1px
;
cursor
:
pointer
;
}
}
.left_desc
{
font-size
:
14px
;
font-weight
:
400
;
color
:
#999999
;
margin
:
14px
0
0
21px
;
}
.left_desc_active
{
color
:
#aa1941
;
}
}
.footer_right
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
flex-end
;
.right_top
{
display
:
flex
;
.top_tit
{
font-size
:
16px
;
font-weight
:
400
;
line-height
:
34px
;
color
:
#333333
;
}
.top_price
{
display
:
flex
;
margin-left
:
53px
;
.price_icon
{
font-size
:
22px
;
font-weight
:
500
;
line-height
:
34px
;
color
:
#aa1941
;
}
.price_num
{
font-size
:
36px
;
font-weight
:
normal
;
line-height
:
34px
;
color
:
#aa1941
;
}
}
}
.right_btn
{
width
:
153px
;
height
:
48px
;
background
:
#edb24c
;
border-radius
:
24px
;
font-size
:
18px
;
font-weight
:
400
;
line-height
:
48px
;
color
:
#ffffff
;
text-align
:
center
;
margin-top
:
20px
;
cursor
:
pointer
;
}
}
}
}
}
:deep
(
.el-radio
)
{
width
:
220px
;
height
:
83px
;
background
:
#ffffff
;
border
:
2px
solid
#e2e2e2
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
}
:deep
(
.el-radio.is-bordered.is-checked
)
{
border
:
2px
solid
#ebaf48
;
background
:
rgba
(
255
,
251
,
245
,
0
.39
);
}
:deep
(
.el-radio__input
)
{
display
:
none
;
}
:deep
(
.el-radio__label
)
{
img
{
margin-right
:
10px
;
}
.radio_tit
{
font-size
:
16px
;
font-weight
:
400
;
line-height
:
34px
;
color
:
#666666
;
}
}
:deep
(
.el-checkbox__input.is-checked
.el-checkbox__inner
)
{
background
:
#e3a232
;
border-color
:
#e3a232
;
}
</
style
>
src/modules/pay/components/PayH5.vue
0 → 100644
浏览文件 @
2daf00e0
<
script
setup
lang=
"ts"
>
import
{
Check
}
from
'@element-plus/icons-vue'
import
{
ElMessage
}
from
'element-plus'
import
{
getDateTime
}
from
'@/utils'
import
{
useUserStore
}
from
'@/stores/user'
import
{
usePay
}
from
'../composables/usePay'
import
{
useStorage
}
from
'@vueuse/core'
const
props
=
defineProps
({
shopItem
:
{
type
:
Object
,
default
:
()
=>
({})
}
})
const
emit
=
defineEmits
([
'success'
])
const
route
=
useRoute
()
const
router
=
useRouter
()
const
userStore
=
useUserStore
()
const
params
=
$
(
useStorage
(
'params'
,
{
payment_method
:
'11'
}))
const
start_time
=
getDateTime
()
const
end_time
=
getDateTime
(
90
)
const
isAgree
=
$ref
(
false
)
let
isAgreeText
=
$ref
(
false
)
const
dialogVisible
=
$ref
(
false
)
const
{
order
,
pay
}
=
usePay
()
onMounted
(()
=>
{
if
(
route
.
query
.
is_pay
)
{
pay
(
params
)
}
})
watchEffect
(()
=>
{
if
(
order
.
value
?.
order_status
===
'4'
)
{
// 支付成功
console
.
log
(
'支付成功'
)
emit
(
'success'
,
order
.
value
)
}
})
// 去支付
function
handlePay
()
{
if
(
!
isAgree
)
{
isAgreeText
=
true
ElMessage
.
warning
(
'请先勾选紫荆金保服务协议'
)
return
}
pay
(
params
)
}
const
handlePrev
=
()
=>
{
router
.
push
({
path
:
`/shop/detail/
${
props
.
shopItem
?.
id
}
`
})
}
const checkedChange = (val: string) => {
params.payment_method = val
}
</
script
>
<
template
>
<div>
<div
class=
"main_con"
>
<div
class=
"con_nav"
@
click=
"handlePrev"
>
<img
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/prev_mini.png"
/>
<div
class=
"nav_title"
>
确认订单
</div>
</div>
<div
class=
"course_con"
>
<img
:src=
"
shopItem?.image_url ||
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fb%2F56e7995e3501f.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671671981&t=0eb627c761e6567a3a0a29163b31aac0'
"
/>
<div
class=
"course_dec"
>
<div
class=
"info_title"
>
{{
shopItem
.
title
}}
</div>
<div
class=
"info_date"
>
有效期:
{{
start_time
}}
至
{{
end_time
}}
</div>
</div>
</div>
<div
class=
"pay_con"
>
<div
class=
"pay_phone"
>
课程提醒将发送到您的手机:
<i
style=
"font-weight: bold"
>
{{
userStore
.
user
?.
mobile
}}
</i>
</div>
<div
class=
"pay_line"
></div>
<div
class=
"pay_mode"
>
<div
class=
"mode_item"
>
<img
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/pay_ali.png"
/>
<div
class=
"radio_tit"
>
支付宝支付
</div>
<div
:class=
"
params.payment_method === '12'
? 'radio_check_active'
: 'radio_check'
"
@
click=
"checkedChange('12')"
>
<template
v-if=
"params.payment_method === '12'"
>
<el-icon><Check
/></el-icon>
</
template
>
</div>
</div>
<div
class=
"mode_item"
>
<img
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/pay_wechat.png"
/>
<div
class=
"radio_tit"
>
微信支付
</div>
<div
:class=
"
params.payment_method === '4'
? 'radio_check_active'
: 'radio_check'
"
@
click=
"checkedChange('4')"
>
<
template
v-if=
"params.payment_method === '4'"
>
<el-icon><Check
/></el-icon>
</
template
>
</div>
</div>
</div>
</div>
<div
class=
"argreement_con"
>
<div
class=
"left_top"
>
<el-checkbox
v-model=
"isAgree"
>
<span>
同意
</span>
</el-checkbox>
<a
@
click=
"dialogVisible = true"
>
紫荆金保服务协议
</a>
</div>
<div
class=
"left_desc"
:class=
"isAgreeText === true ? 'left_desc_active' : ''"
>
请先勾选紫荆金保服务协议
</div>
</div>
<div
class=
"to_pay_main"
@
click=
"handlePay"
>
<div
class=
"pay_price"
>
<span
class=
"to_pay"
>
立即支付
</span>
<span
class=
"to_price"
><i
style=
"font-size: 12px"
>
¥
</i>
1999.00
</span>
</div>
</div>
</div>
<!-- <el-dialog v-model="dialogVisible" :width="!mobile ? '50%' : '90%'">
<div v-else style="height: 8rem">
<iframe
:src="`https://view.xdocin.com/xdoc?_xdoc=${item?.url}`"
frameborder="0"
width="100%"
height="100%"></iframe>
</div>
<template #footer>
<el-button type="primary" @click="changeProtocol" style="background-color: #e3a232; border: none"
>我已阅读并同意</el-button
>
</template>
</el-dialog> -->
</div>
</template>
<
style
lang=
"scss"
scoped
>
.main_con
{
padding
:
0
0
.28rem
;
.con_nav
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
position
:
relative
;
img
{
position
:
absolute
;
left
:
0
;
}
.nav_title
{
font-size
:
0
.32rem
;
font-weight
:
500
;
line-height
:
0
.34rem
;
color
:
#333333
;
}
}
.course_con
{
margin
:
0
.3rem
0
;
height
:
1
.97rem
;
background
:
#ffffff
;
opacity
:
1
;
border-radius
:
0
.12rem
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
padding
:
0
.28rem
0
.2rem
;
box-sizing
:
border-box
;
gap
:
0
.2rem
;
img
{
width
:
2
.2rem
;
height
:
1
.4rem
;
}
.course_dec
{
display
:
flex
;
flex-direction
:
column
;
gap
:
0
.2rem
;
.info_title
{
height
:
0
.64rem
;
font-size
:
0
.28rem
;
font-weight
:
500
;
line-height
:
0
.36rem
;
color
:
#333333
;
}
.info_date
{
font-size
:
0
.22rem
;
font-weight
:
400
;
line-height
:
0
.3rem
;
color
:
#999999
;
white-space
:
nowrap
;
}
}
}
.pay_con
{
width
:
6
.9rem
;
box-sizing
:
border-box
;
margin-bottom
:
0
.53rem
;
background
:
#fff
;
border-radius
:
0
.12rem
;
padding
:
0
.54rem
0
.4rem
;
.pay_phone
{
text-align
:
center
;
font-size
:
0
.24rem
;
color
:
#333333
;
}
.pay_line
{
height
:
0px
;
border
:
1px
solid
#f8f8f8
;
opacity
:
1
;
margin
:
0
.57rem
0
0
.54rem
0
;
}
.pay_mode
{
display
:
flex
;
flex-direction
:
column
;
gap
:
0
.4rem
;
.mode_item
{
display
:
flex
;
align-items
:
center
;
position
:
relative
;
img
{
width
:
0
.3rem
;
height
:
0
.3rem
;
}
.radio_tit
{
margin-left
:
0
.2rem
;
}
.radio_check_active
{
position
:
absolute
;
right
:
0
;
width
:
0
.25rem
;
height
:
0
.25rem
;
border-radius
:
50%
;
display
:
flex
;
align-items
:
center
;
font-size
:
12px
;
color
:
#fff
;
background-color
:
#f1b44e
;
box-sizing
:
border-box
;
}
.radio_check
{
position
:
absolute
;
right
:
0
;
width
:
0
.25rem
;
height
:
0
.25rem
;
border
:
1px
solid
#707070
;
border-radius
:
50%
;
display
:
flex
;
align-items
:
center
;
font-size
:
12px
;
color
:
#fff
;
box-sizing
:
border-box
;
}
}
}
}
.argreement_con
{
text-align
:
center
;
.left_top
{
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
.el-checkbox__label
{
span
{
color
:
#666666
;
font-size
:
0
.24rem
;
font-weight
:
400
;
}
}
a
{
font-weight
:
400
;
font-size
:
0
.24rem
;
color
:
#e3a232
!
important
;
margin-top
:
0
.02rem
;
cursor
:
pointer
;
}
}
.left_desc
{
color
:
#999999
;
font-size
:
0
.24rem
;
margin-left
:
0
.9rem
;
}
.left_desc_active
{
color
:
#aa1941
;
}
}
.to_pay_main
{
margin
:
3
.5rem
-0
.3rem
0
;
height
:
1
.2rem
;
background
:
#fff
;
opacity
:
1
;
border-radius
:
0
.2rem
0
.2rem
0px
0px
;
padding
:
0
.24rem
0
.3rem
0
.16rem
0
.3rem
;
box-sizing
:
border-box
;
.pay_price
{
width
:
100%
;
height
:
0
.8rem
;
background
:
linear-gradient
(
102deg
,
#f2ca8c
0%
,
#e69b1c
100%
);
border-radius
:
0
.4rem
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
color
:
#fff
;
gap
:
0
.18rem
;
.to_pay
{
font-size
:
0
.28rem
;
}
.to_price
{
font-size
:
0
.4rem
;
}
}
}
}
:deep
(
.el-radio
)
{
width
:
220px
;
height
:
83px
;
background
:
#ffffff
;
border
:
2px
solid
#e2e2e2
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
}
:deep
(
.el-radio.is-bordered.is-checked
)
{
border
:
2px
solid
#ebaf48
;
background
:
rgba
(
255
,
251
,
245
,
0
.39
);
}
:deep
(
.el-radio__input
)
{
display
:
none
;
}
:deep
(
.el-radio__label
)
{
img
{
margin-right
:
10px
;
}
.radio_tit
{
font-size
:
16px
;
font-weight
:
400
;
line-height
:
34px
;
color
:
#666666
;
}
}
:deep
(
.el-checkbox__input.is-checked
.el-checkbox__inner
)
{
background
:
#e3a232
;
border-color
:
#e3a232
;
}
</
style
>
src/modules/pay/components/PayPC.vue
0 → 100644
浏览文件 @
2daf00e0
<
script
setup
lang=
"ts"
>
import
QrcodeVue
from
'qrcode.vue'
import
{
ElMessage
}
from
'element-plus'
import
{
getDateTime
}
from
'@/utils'
import
{
useUserStore
}
from
'@/stores/user'
import
{
usePay
}
from
'../composables/usePay'
defineProps
({
shopItem
:
{
type
:
Object
,
default
:
()
=>
({})
}
})
const
emit
=
defineEmits
([
'success'
])
const
userStore
=
useUserStore
()
const
params
=
reactive
({
payment_method
:
'11'
})
const
start_time
=
getDateTime
()
const
end_time
=
getDateTime
(
90
)
let
isAgree
=
$ref
(
false
)
let
isAgreeText
=
$ref
(
false
)
const
{
order
,
payOrder
,
pay
}
=
usePay
()
watchEffect
(()
=>
{
if
(
order
.
value
?.
order_status
===
'4'
)
{
// 支付成功
console
.
log
(
'支付成功'
)
emit
(
'success'
,
order
.
value
)
}
})
// 去支付
function
handlePay
()
{
if
(
!
isAgree
)
{
isAgreeText
=
true
ElMessage
.
warning
(
'请先勾选紫荆金保服务协议'
)
return
}
pay
(
params
)
}
const
handleAgree
=
(
val
:
any
)
=>
{
console
.
log
(
val
)
isAgree
=
val
if
(
val
===
true
)
{
isAgreeText
=
false
}
}
const
handleClose
=
()
=>
{
isAgree
=
true
isAgreeText
=
false
}
const
handleAgreement
=
()
=>
{
window
.
open
(
'https://webapp-pub.oss-cn-beijing.aliyuncs.com/project/sbu-plus/%E8%AF%AD%E8%A8%80%E5%BC%BA%E5%8C%96%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D.pdf'
)
}
</
script
>
<
template
>
<div
class=
"main_con"
v-if=
"!order"
>
<div
class=
"con_tit"
>
课程信息确认
</div>
<div
class=
"con_pay"
>
<div
class=
"pay_course"
>
<img
:src=
"
shopItem.image_url ||
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fb%2F56e7995e3501f.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671671981&t=0eb627c761e6567a3a0a29163b31aac0'
"
/>
<div
class=
"course_info"
>
<div
class=
"info_tit"
>
{{
shopItem
.
title
}}
</div>
<div
class=
"info_range"
>
有效期:
{{
start_time
}}
至
{{
end_time
}}
</div>
<div
class=
"info_price"
>
<div
class=
"price_icon"
>
¥
</div>
<div
class=
"price_num"
>
{{
shopItem
.
price
}}
</div>
</div>
</div>
</div>
<div
class=
"con_message"
>
课程提醒将发送到您的手机:
{{
userStore
.
user
?.
mobile
}}
</div>
<div
class=
"con_mode"
>
<div
class=
"mode_tit"
>
支付方式
</div>
<div
class=
"mode_radio"
>
<el-radio-group
v-model=
"params.payment_method"
>
<el-radio
label=
"11"
size=
"large"
border
>
<img
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/pay_ali.png"
/>
<span
class=
"radio_tit"
>
支付宝支付
</span>
</el-radio>
<el-radio
label=
"1"
size=
"large"
border
>
<img
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/pay_wechat.png"
/>
<span
class=
"radio_tit"
>
微信支付
</span>
</el-radio>
</el-radio-group>
</div>
</div>
<div
class=
"con_footer"
>
<div
class=
"footer_left"
>
<div
class=
"left_top"
>
<el-checkbox
v-model=
"isAgree"
@
change=
"handleAgree"
>
<span>
同意
</span></el-checkbox
>
<a
@
click=
"handleAgreement"
>
紫荆金保服务协议
</a>
</div>
<div
class=
"left_desc"
:class=
"isAgreeText ? 'left_desc_active' : ''"
>
请先勾选紫荆金保服务协议
</div>
</div>
<div
class=
"footer_right"
>
<div
class=
"right_top"
>
<div
class=
"top_tit"
>
需付金额:
</div>
<div
class=
"top_price"
>
<div
class=
"price_icon"
>
¥
</div>
<div
class=
"price_num"
>
{{
shopItem
.
price
}}
</div>
</div>
</div>
<div
class=
"right_btn"
@
click=
"handlePay"
>
立即支付
</div>
</div>
</div>
</div>
</div>
<div
class=
"main"
v-else
>
<div
class=
"main_order"
>
<div
class=
"order_id"
>
<div
class=
"id_tit"
>
商品订单:
</div>
<div
class=
"id_num"
>
{{
order
.
order_id
}}
</div>
</div>
<div
class=
"order_price"
>
<div
class=
"price_tit"
>
支付金额:
</div>
<div
class=
"price_con"
>
<div
class=
"con_icon"
>
¥
</div>
<div
class=
"con_num"
>
{{
order
.
payment_money
}}
</div>
</div>
</div>
<div
class=
"line"
></div>
<div
class=
"order_mode"
>
<div
class=
"mode_tit"
>
支付方式:
</div>
<div
class=
"mode_con"
>
<img
:src=
"
order.payment_method === '11'
? 'https://webapp-pub.ezijing.com/project_online/fi/pay_ali.png'
: 'https://webapp-pub.ezijing.com/project_online/fi/pay_wechat.png'
"
class=
"con_style"
/>
<span
class=
"radio_tit"
>
{{
order
.
payment_method
===
'11'
?
'支付宝支付'
:
'微信支付'
}}
</span>
<img
src=
"https://webapp-pub.ezijing.com/project_online/fi/icon_pay_checked.png"
class=
"checked_img"
/>
</div>
</div>
<div
class=
"order_qaCode"
>
<div
class=
"qaCode_left"
>
<div
class=
"left_code"
>
<qrcode-vue
:value=
"payOrder?.payment_url"
:size=
"197"
level=
"H"
></qrcode-vue>
</div>
<div
class=
"left_desc"
:class=
"
order.payment_method === '11'
? 'left_desc_ali'
: 'left_desc_wechat'
"
>
{{
order
.
payment_method
===
'11'
?
'请打开手机支付宝,扫一扫完成支付'
:
'请打开手机微信,扫一扫完成支付'
}}
</div>
</div>
<img
:src=
"
order.payment_method === '11'
? 'https://webapp-pub.ezijing.com/project_online/fi/icon_aliPay_img1.png'
: 'https://webapp-pub.ezijing.com/project_online/fi/icon_wechat_img1.png'
"
class=
"right_img"
/>
</div>
</div>
</div>
<AgreementDialog
v-if=
"dialogVisible === true"
v-model:dialogVisible=
"dialogVisible"
:mobile=
"'1'"
@
close=
"handleClose"
/>
</
template
>
<
style
lang=
"scss"
scoped
>
.main_con
{
width
:
1200px
;
margin
:
auto
;
.con_tit
{
font-size
:
28px
;
font-weight
:
500
;
line-height
:
34px
;
color
:
#333333
;
padding-top
:
39px
;
}
.con_pay
{
height
:
721px
;
background
:
#ffffff
;
margin-top
:
26px
;
padding
:
52px
60px
107px
40px
;
box-sizing
:
border-box
;
.pay_course
{
display
:
flex
;
padding-bottom
:
41px
;
border-bottom
:
1px
solid
#e6e6e6
;
img
{
width
:
257px
;
height
:
166px
;
}
.course_info
{
margin-left
:
35px
;
.info_tit
{
font-size
:
24px
;
font-weight
:
500
;
line-height
:
34px
;
color
:
#333333
;
}
.info_range
{
font-size
:
14px
;
font-weight
:
400
;
line-height
:
34px
;
color
:
#666666
;
margin-top
:
26px
;
}
.info_price
{
display
:
flex
;
align-items
:
flex-end
;
margin-top
:
42px
;
.price_icon
{
font-size
:
20px
;
font-weight
:
500
;
color
:
#aa1941
;
}
.price_num
{
font-size
:
30px
;
font-weight
:
normal
;
line-height
:
34px
;
color
:
#aa1941
;
}
}
}
}
}
.con_message
{
margin-top
:
30px
;
font-size
:
18px
;
font-weight
:
500
;
line-height
:
34px
;
color
:
#333333
;
}
.con_mode
{
margin-top
:
43px
;
display
:
flex
;
align-items
:
center
;
.mode_tit
{
font-size
:
16px
;
font-weight
:
400
;
line-height
:
34px
;
color
:
#333333
;
}
.mode_radio
{
margin-left
:
44px
;
}
}
.con_footer
{
margin-top
:
74px
;
display
:
flex
;
justify-content
:
space-between
;
.footer_left
{
padding-top
:
12px
;
.left_top
{
display
:
flex
;
align-items
:
center
;
.el-checkbox__label
{
span
{
color
:
#666666
;
font-size
:
16px
;
font-weight
:
400
;
}
}
a
{
color
:
#e3a232
;
font-size
:
16px
;
font-weight
:
400
;
margin-top
:
-1px
;
cursor
:
pointer
;
}
}
.left_desc
{
font-size
:
14px
;
font-weight
:
400
;
color
:
#999999
;
margin
:
14px
0
0
21px
;
}
.left_desc_active
{
color
:
#aa1941
;
}
}
.footer_right
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
flex-end
;
.right_top
{
display
:
flex
;
.top_tit
{
font-size
:
16px
;
font-weight
:
400
;
line-height
:
34px
;
color
:
#333333
;
}
.top_price
{
display
:
flex
;
margin-left
:
53px
;
.price_icon
{
font-size
:
22px
;
font-weight
:
500
;
line-height
:
34px
;
color
:
#aa1941
;
}
.price_num
{
font-size
:
36px
;
font-weight
:
normal
;
line-height
:
34px
;
color
:
#aa1941
;
}
}
}
.right_btn
{
width
:
153px
;
height
:
48px
;
background
:
#edb24c
;
border-radius
:
24px
;
font-size
:
18px
;
font-weight
:
400
;
line-height
:
48px
;
color
:
#ffffff
;
text-align
:
center
;
margin-top
:
20px
;
cursor
:
pointer
;
}
}
}
}
:deep
(
.el-radio
)
{
width
:
220px
;
height
:
83px
;
background
:
#ffffff
;
border
:
2px
solid
#e2e2e2
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
}
:deep
(
.el-radio.is-bordered.is-checked
)
{
border
:
2px
solid
#ebaf48
;
background
:
rgba
(
255
,
251
,
245
,
0
.39
);
}
:deep
(
.el-radio__input
)
{
display
:
none
;
}
:deep
(
.el-radio__label
)
{
img
{
margin-right
:
10px
;
}
.radio_tit
{
font-size
:
16px
;
font-weight
:
400
;
line-height
:
34px
;
color
:
#666666
;
}
}
:deep
(
.el-checkbox__input.is-checked
.el-checkbox__inner
)
{
background
:
#e3a232
;
border-color
:
#e3a232
;
}
.main
{
width
:
100%
;
padding
:
50px
0
46px
0
;
.main_order
{
width
:
1200px
;
background
:
#ffffff
;
margin
:
auto
;
padding
:
59px
0
137px
40px
;
.order_id
{
display
:
flex
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
34px
;
.id_tit
{
color
:
#333333
;
}
.id_num
{
color
:
#999999
;
}
}
.order_price
{
display
:
flex
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
34px
;
margin-top
:
22px
;
.price_tit
{
color
:
#333333
;
}
.price_con
{
display
:
flex
;
.con_icon
{
font-size
:
22px
;
font-weight
:
400
;
line-height
:
34px
;
color
:
#aa1941
;
}
.con_num
{
font-size
:
36px
;
font-weight
:
normal
;
line-height
:
34px
;
color
:
#aa1941
;
}
}
}
.line
{
margin-top
:
26px
;
border-bottom
:
1px
solid
#e6e6e6
;
}
.order_mode
{
.mode_tit
{
font-size
:
16px
;
font-weight
:
500
;
line-height
:
34px
;
color
:
#333333
;
}
.mode_con
{
margin-top
:
29px
;
width
:
160px
;
height
:
66px
;
border
:
1px
solid
#4586d0
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
position
:
relative
;
.con_style
{
margin-right
:
10px
;
}
.checked_img
{
position
:
absolute
;
right
:
-1px
;
bottom
:
-1px
;
}
}
}
.order_qaCode
{
display
:
flex
;
margin-top
:
39px
;
.qaCode_left
{
.left_code
{
width
:
197px
;
}
.left_desc
{
width
:
197px
;
height
:
31px
;
font-size
:
12px
;
font-weight
:
400
;
line-height
:
31px
;
color
:
#ffffff
;
text-align
:
center
;
}
.left_desc_ali
{
background
:
#0f76fb
;
}
.left_desc_wechat
{
background
:
#01c71e
;
}
}
.right_img
{
margin
:
-11px
0
0
124px
;
}
}
}
}
</
style
>
src/modules/pay/composables/usePay.ts
0 → 100644
浏览文件 @
2daf00e0
import
type
{
PayOrder
,
Order
}
from
'../types'
import
*
as
api
from
'../api'
import
{
useUserStore
}
from
'@/stores/user'
import
{
useShopStore
}
from
'@/stores/shop'
import
{
useStorage
}
from
'@vueuse/core'
import
{
useDevice
}
from
'@/composables/useDevice'
const
{
wechat
}
=
useDevice
()
export
function
usePay
()
{
const
route
=
useRoute
()
const
userStore
=
useUserStore
()
const
shopStore
=
useShopStore
()
// 订单信息
const
order
=
ref
<
Order
>
()
// 支付的订单信息
const
payOrder
=
ref
<
PayOrder
>
()
const
openId
=
useStorage
(
'openId'
,
''
)
// 支付
async
function
pay
(
options
=
{})
{
// 默认参数
const
defaultParams
:
Record
<
string
,
any
>
=
reactive
({
shop_id
:
shopStore
.
shopItem
?.
shop_id
||
'6998523899570814976'
,
spu_id
:
shopStore
.
shopItem
?.
spu_id
||
'6998525810348916736'
,
sku_id
:
shopStore
.
shopItem
?.
sku_id
||
'6998525810365693952'
,
buy_count
:
'1'
,
redirect_url
:
`
${
location
.
origin
}
/shop/order/
${
shopStore
.
shopItem
?.
id
}
`,
notify_url: `
https
:
//ep-lms-api.ezijing.com/v2/student/push?tenant=paa&sso_id=${userStore.user?.id}&class_id=${shopStore.shopItem?.class_id}&course_flag=1&course_id=${shopStore.shopItem?.course_id}`
}
)
const params = Object.assign(defaultParams, options)
// 微信JS支付参数设置
if (wechat.value && params.payment_method === '4') {
params.payment_method = '3'
params.open_id = await getOpenId()
}
// 创建订单
await createOrder(params)
if (!payOrder.value) return
// 网页支付,直接唤起对应支付网页
if (params.payment_method === '4' || params.payment_method === '12') {
location.href = payOrder.value.payment_url
return
}
// 微信JS支付
if (params.payment_method === '3') {
wxJSPay()
}
// 检测订单信息
checkOrder()
}
// 创建订单
async function createOrder(params: any) {
const res: any = await api.createOrder(params)
payOrder.value = res
localStorage.setItem('order_detail_id', res.order_detail_id)
await getOrder()
return res
}
// 获取订单信息
async function getOrder() {
if (!payOrder.value) return
const res = await api.getOrderList({ order_detail_id: payOrder.value.order_detail_id })
const currentOrder = res.data[0]
order.value = currentOrder
return currentOrder
}
// 检测订单状态
let timer = 0
async function checkOrder() {
if (!payOrder.value) return
timer && clearInterval(timer)
timer = setInterval(async () => {
const currentOrder = await getOrder()
if (currentOrder?.order_status === '4') clearInterval(timer)
}, 2000)
}
onUnmounted(() => {
timer && clearInterval(timer)
})
// 微信支付相关
// 获取code
function getCode() {
const href = location.href.includes('?') ? `
$
{
location
.
href
}
&
is_pay
=
true
` : `
$
{
location
.
href
}?
is_pay
=
true
`
const redirectURI = `
https
:
//pages.ezijing.com/given/auth.html?redirect_uri=${encodeURIComponent(href)}`
location
.
href
=
`https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx451c01d40d090d7a&redirect_uri=
${
redirectURI
}
&response_type=code&scope=snsapi_base`
}
// 获取openId
async
function
getOpenId
()
{
if
(
openId
.
value
)
return
openId
.
value
const
code
=
route
.
query
.
code
||
getCode
()
return
api
.
getOpenId
({
code
,
identity
:
'ezijing'
})
.
then
((
res
:
any
)
=>
{
openId
.
value
=
res
.
openid
return
res
.
data
.
openid
})
.
catch
(
getCode
)
}
function
wxJSPay
()
{
if
(
!
payOrder
.
value
?.
payment_more_info
)
{
alert
(
'订单创建错误'
)
return
}
const
payInfo
:
any
=
JSON
.
parse
(
payOrder
.
value
.
payment_more_info
)
;(
window
as
any
).
WeixinJSBridge
?.
invoke
(
'getBrandWCPayRequest'
,
payInfo
,
(
res
:
any
)
=>
{
console
.
log
(
res
)
})
}
return
{
order
,
payOrder
,
pay
}
}
src/modules/pay/index.ts
浏览文件 @
2daf00e0
...
@@ -5,6 +5,19 @@ export const routes: Array<RouteRecordRaw> = [
...
@@ -5,6 +5,19 @@ export const routes: Array<RouteRecordRaw> = [
{
{
path
:
'/shop/pay'
,
path
:
'/shop/pay'
,
component
:
AppLayout
,
component
:
AppLayout
,
children
:
[{
path
:
'/shop/pay/:id'
,
component
:
()
=>
import
(
'./views/Index.vue'
),
props
:
true
}]
children
:
[
{
path
:
'/shop/pay/:id'
,
component
:
()
=>
import
(
'./views/Index.vue'
),
props
:
true
,
meta
:
{
loginRequired
:
true
}
},
{
path
:
'/shop/order/:id'
,
component
:
()
=>
import
(
'./views/Order.vue'
),
props
:
true
,
meta
:
{
loginRequired
:
true
}
}
]
}
}
]
]
src/modules/pay/type.ts
0 → 100644
浏览文件 @
2daf00e0
// 创建订单之后生成的订单信息
export
interface
PayOrder
{
order_id
:
string
order_detail_id
:
string
payment_order_id
:
string
pay_order_id
:
string
payment_url
:
string
payment_more_info
:
string
}
// 订单信息
export
interface
Order
{
order_id
:
string
order_detail_id
:
string
shop_id
:
string
spu_id
:
string
sku_id
:
string
spu_name
:
string
chart_oss
:
string
buy_count
:
string
customer_id
:
string
customer_phone
:
string
product_price
:
string
district_money
:
string
payment_money
:
string
shipping_user
:
string
shipping_phone
:
string
payment_method
:
string
app_button_text
:
string
payment_order_id
:
string
pay_order_id
:
string
create_time
:
string
order_status
:
string
update_time
:
string
pay_time
:
string
}
\ No newline at end of file
src/modules/pay/views/Index.vue
浏览文件 @
2daf00e0
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
Confirm
from
'../components/Confirm.vue'
import
type
{
Order
}
from
'../types'
import
Order
from
'../components/Order.vue'
import
PaySucess
from
'../components/PaySucess.vue'
import
{
useShopStore
}
from
'@/stores/shop'
import
{
useShopStore
}
from
'@/stores/shop'
import
{
useDevice
}
from
'@/composables/useDevice'
import
{
useDevice
}
from
'@/composables/useDevice'
const
{
mobile
}
=
useDevice
()
const
PayH5
=
defineAsyncComponent
(()
=>
import
(
'../components/PayH5.vue'
))
const
PayPC
=
defineAsyncComponent
(()
=>
import
(
'../components/PayPC.vue'
))
const
{
shopItem
}
=
useShopStore
()
const
{
shopItem
}
=
useShopStore
()
const
status
=
ref
(
'confirm'
)
// confirm | order | success
const
{
mobile
}
=
useDevice
()
const
payMethod
=
ref
(
0
)
const
payInfo
=
ref
({})
const
router
=
useRouter
()
const
handleSuccess
=
(
data
:
any
)
=>
{
const
handleSuccess
=
(
data
:
Order
)
=>
{
payMethod
.
value
=
data
.
payMode
router
.
replace
({
status
.
value
=
data
.
status
path
:
`/shop/order/
${
shopItem
?.
id
}
`,
}
query: { order_detail_id: data.order_detail_id }
const
handleOrder
=
(
data
:
any
)
=>
{
})
payInfo
.
value
=
data
status
.
value
=
data
.
status
}
const
handleSuccessH5
=
(
data
:
any
)
=>
{
payInfo
.
value
=
data
status
.
value
=
data
.
status
}
}
</
script
>
</
script
>
<
template
>
<
template
>
<div
class=
"pay_main"
v-if=
"!mobile"
>
<div
class=
"pay_main"
>
<Confirm
<PayH5
:shopItem=
"shopItem"
@
success=
"handleSuccess"
v-if=
"mobile"
></PayH5>
:shopItem=
"shopItem"
<PayPC
:shopItem=
"shopItem"
@
success=
"handleSuccess"
v-else
></PayPC>
@
success=
"handleSuccess"
v-if=
"status === 'confirm'"
/>
<Order
:shopItem=
"shopItem"
:payMethod=
"payMethod"
@
update=
"handleOrder"
v-if=
"status === 'order'"
/>
<PaySucess
:shopItem=
"shopItem"
:payInfo=
"payInfo"
v-if=
"status === 'success'"
/>
</div>
<div
v-else
>
<Confirm
:shopItem=
"shopItem"
@
success=
"handleSuccessH5"
v-if=
"status === 'confirm'"
/>
<PaySucess
:shopItem=
"shopItem"
:payInfo=
"payInfo"
v-if=
"status === 'success'"
/>
</div>
</div>
</
template
>
</
template
>
...
...
src/modules/pay/
components/PaySucess
.vue
→
src/modules/pay/
views/Order
.vue
浏览文件 @
2daf00e0
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
type
{
Order
}
from
'../types'
import
{
getDateTime
}
from
'@/utils'
import
{
getOrderList
}
from
'../api'
import
{
useDevice
}
from
'@/composables/useDevice'
import
{
useDevice
}
from
'@/composables/useDevice'
import
{
useShopStore
}
from
'@/stores/shop'
import
{
useUserStore
}
from
'@/stores/user'
interface
Props
{
id
:
string
}
const
props
=
defineProps
<
Props
>
()
const
{
shopItem
}
=
useShopStore
()
const
{
mobile
}
=
useDevice
()
const
{
mobile
}
=
useDevice
()
const
router
=
useRouter
()
const
router
=
useRouter
()
const
props
=
defineProps
({
const
route
=
useRoute
()
payInfo
:
{
const
orderId
=
useStorage
(
'order_detail_id'
,
route
.
query
.
order_detail_id
)
type
:
Object
const
order
=
ref
<
Order
>
()
},
async
function
getOrder
()
{
shopItem
:
{
getOrderList
({
order_detail_id
:
orderId
.
value
})
type
:
Object
.
then
((
res
)
=>
{
}
order
.
value
=
res
.
data
[
0
]
})
if
(
order
.
value
?.
order_status
===
'4'
)
{
function
getDateTime
(
dayNum
:
any
)
{
// 支付成功
const
dateDay
=
new
Date
()
// 刷新已购买的课程列表
dateDay
.
setDate
(
dateDay
.
getDate
()
+
dayNum
)
//获取dayNum天后的日期
useUserStore
().
getCourse
()
console
.
log
(
dateDay
)
}
else
{
const
y
=
dateDay
.
getFullYear
()
// 未支付,返回支付页面
const
m
=
router
.
replace
(
`/shop/pay/
${
props
.
id
}
`
)
dateDay
.
getMonth
()
+
1
<
10
}
?
'0'
+
(
dateDay
.
getMonth
()
+
1
)
}
)
:
dateDay
.
getMonth
()
+
1
//获取当前月份的日期,不足10补0
.
catch
(()
=>
{
const
d
=
dateDay
.
getDate
()
<
10
?
'0'
+
dateDay
.
getDate
()
:
dateDay
.
getDate
()
//获取当前几号,不足10补0
router
.
replace
(
`/shop/pay/
${
props
.
id
}
`
)
return
y
+
'-'
+
m
+
'-'
+
d
})
}
}
onMounted
(()
=>
{
getOrder
()
})
const
start_time
=
getDateTime
(
0
)
const
start_time
=
getDateTime
(
0
)
const
end_time
=
getDateTime
(
90
)
const
end_time
=
getDateTime
(
90
)
const
handleStudy
=
()
=>
{
const
handleStudy
=
()
=>
{
window
.
open
(
'https://paa-learning.ezijing.com'
)
window
.
open
(
'https://paa-learning.ezijing.com'
)
}
}
const
handlePrev
=
()
=>
{
const
handlePrev
=
()
=>
{
router
.
replace
({
router
.
replace
({
path
:
`/shop/detail/
${
shopItem
?.
id
}
` })
path
:
`/shop/detail/
${
props
.
shopItem
?.
id
}
`,
query: {
payStatus: props.payInfo?.payStatus
}
})
}
}
</
script
>
</
script
>
<
template
>
<
template
>
<div
class=
"main_pay"
v-if=
"!mobile"
>
<div
class=
"pay_main"
v-if=
"order"
>
<div
class=
"pay_con"
>
<div
class=
"main_pay"
v-if=
"!mobile"
>
<div
class=
"con_top"
>
<div
class=
"pay_con"
>
<img
<div
class=
"con_top"
>
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/icon_sucess.png"
<img
alt=
""
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/icon_sucess.png"
/>
/>
<div
class=
"top_tit"
>
支付成功!
</div>
<div
class=
"top_tit"
>
支付成功!
</div>
</div>
<div
class=
"con_info"
>
<div
class=
"info_order"
>
<div
class=
"order_tit"
>
商品订单:
</div>
<div
class=
"order_id"
>
{{
payInfo
?.
orderId
}}
</div>
</div>
</div>
<div
class=
"info_price"
>
<div
class=
"con_info"
>
<div
class=
"price_tit"
>
支付金额:
</div>
<div
class=
"info_order"
>
<div
class=
"price_id"
>
¥
{{
payInfo
?.
payPrice
}}
</div>
<div
class=
"order_tit"
>
商品订单:
</div>
</div>
<div
class=
"order_id"
>
{{
order
.
order_id
}}
</div>
<div
class=
"info_tips"
>
</div>
若有疑问请与客服联系,我们将尽快为您提供服务
<div
class=
"info_price"
>
</div>
<div
class=
"price_tit"
>
支付金额:
</div>
<div
class=
"info_btn"
>
<div
class=
"price_id"
>
¥
{{
order
.
payment_money
}}
</div>
<div
class=
"btn_prev"
@
click=
"handlePrev"
>
返回
</div>
</div>
<div
class=
"btn_study"
@
click=
"handleStudy"
>
开始学习
</div>
<div
class=
"info_tips"
>
若有疑问请与客服联系,我们将尽快为您提供服务
</div>
<div
class=
"info_btn"
>
<div
class=
"btn_prev"
@
click=
"handlePrev"
>
返回
</div>
<div
class=
"btn_study"
@
click=
"handleStudy"
>
开始学习
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"main_pay_mobile"
v-else
>
<div
class=
"main_pay_mobile"
v-else
>
<div
class=
"con_nav"
>
<div
class=
"con_nav"
>
<img
class=
"img1"
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/prev_mini.png"
alt=
""
srcset=
""
@
click=
"handlePrev"
/>
<div
class=
"nav_title"
>
<img
<img
class=
"img
2
"
class=
"img
1
"
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/
icon_sucess
.png"
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/
prev_mini
.png"
alt=
"
"
@
click=
"handlePrev
"
/>
/>
支付成功
<div
class=
"nav_title"
>
</div>
<img
</div>
class=
"img2"
<div
class=
"course_con"
>
src=
"https://webapp-pub.oss-cn-beijing.aliyuncs.com/project_online/fi/icon_sucess.png"
<img
/>
src=
"https://img1.baidu.com/it/u=3009731526,373851691&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500"
支付成功
@
click=
"handlePrev"
</div>
/>
<div
class=
"course_dec"
>
<div
class=
"info_title"
>
{{
shopItem
?.
title
}}
</div>
<div
class=
"info_date"
>
有效期:
{{
start_time
}}
至
{{
end_time
}}
</div>
</div>
</div>
</div>
<div
class=
"course_con"
>
<div
class=
"order_main"
>
<img
<div
class=
"order_num"
>
src=
"https://img1.baidu.com/it/u=3009731526,373851691&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500"
商品订单:
<span>
{{
payInfo
?.
orderId
}}
</span>
@
click=
"handlePrev"
/>
<div
class=
"course_dec"
>
<div
class=
"info_title"
>
{{
shopItem
?.
title
}}
</div>
<div
class=
"info_date"
>
有效期:
{{
start_time
}}
至
{{
end_time
}}
</div>
</div>
</div>
</div>
<div
class=
"order_price"
>
<div
class=
"order_main"
>
支付金额:
<span>
{{
payInfo
?.
payPrice
}}
</span>
<div
class=
"order_num"
>
商品订单:
<span>
{{
order
.
order_id
}}
</span>
</div>
<div
class=
"order_price"
>
支付金额:
<span>
{{
order
.
payment_money
}}
</span>
</div>
<div
class=
"order_after_sales"
>
若有疑问请与客服联系,我们将尽快为您提供服务
</div>
</div>
</div>
<div
class=
"
order_after_sales
"
>
<div
class=
"
start_study
"
>
若有疑问请与客服联系,我们将尽快为您提供服务
<div
class=
"study_con"
@
click=
"handleStudy"
>
开始学习
</div>
</div>
</div>
</div>
</div>
<div
class=
"start_study"
>
<div
class=
"study_con"
@
click=
"handleStudy"
>
开始学习
</div>
</div>
</div>
</div>
</
template
>
</
template
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.pay_main
{
background
:
#f7f8fa
;
}
.is-h5
{
.is-h5
{
.main_pay_mobile
{
.main_pay_mobile
{
padding
:
0
0
.28rem
;
padding
:
0
0
.28rem
;
...
...
src/router/index.ts
浏览文件 @
2daf00e0
import
{
createRouter
,
createWebHistory
}
from
'vue-router'
import
{
createRouter
,
createWebHistory
}
from
'vue-router'
//
import { useUserStore } from '@/stores/user'
import
{
useUserStore
}
from
'@/stores/user'
const
router
=
createRouter
({
const
router
=
createRouter
({
scrollBehavior
(
to
)
{
scrollBehavior
(
to
)
{
...
@@ -13,10 +13,20 @@ const router = createRouter({
...
@@ -13,10 +13,20 @@ const router = createRouter({
routes
:
[{
path
:
'/:pathMatch(.*)*'
,
redirect
:
'/home'
}]
routes
:
[{
path
:
'/:pathMatch(.*)*'
,
redirect
:
'/home'
}]
})
})
// router.beforeEach((to, from, next) => {
router
.
beforeEach
(
async
(
to
,
from
,
next
)
=>
{
// const user = useUserStore()
const
user
=
useUserStore
()
// user.getUser()
if
(
to
.
meta
.
loginRequired
&&
!
user
.
isLogin
)
{
// next()
try
{
// })
await
user
.
getUser
()
}
catch
(
e
)
{
console
.
error
(
e
)
}
if
(
!
user
.
isLogin
)
{
location
.
href
=
`
${
import
.
meta
.
env
.
VITE_LOGIN_URL
}
?rd=
${
encodeURIComponent
(
location
.
href
)}
`
return
}
}
next
()
})
export
default
router
export
default
router
src/stores/user.ts
浏览文件 @
2daf00e0
...
@@ -26,17 +26,17 @@ export const useUserStore = defineStore({
...
@@ -26,17 +26,17 @@ export const useUserStore = defineStore({
actions
:
{
actions
:
{
async
getUser
()
{
async
getUser
()
{
const
res
=
await
getUser
()
const
res
=
await
getUser
()
try
{
await
this
.
getCourse
()
this
.
courses
=
await
getBuyShop
()
}
catch
(
error
)
{
console
.
log
(
error
)
}
this
.
user
=
res
.
data
this
.
user
=
res
.
data
},
},
async
logout
()
{
async
logout
()
{
await
logout
()
await
logout
()
this
.
user
=
null
this
.
user
=
null
},
async
getCourse
()
{
this
.
courses
=
await
getBuyShop
()
}
}
}
}
})
})
src/utils/index.ts
0 → 100644
浏览文件 @
2daf00e0
export
function
getDateTime
(
dayNum
=
0
)
{
const
dateDay
=
new
Date
()
dateDay
.
setDate
(
dateDay
.
getDate
()
+
dayNum
)
//获取dayNum天后的日期
const
y
=
dateDay
.
getFullYear
()
const
m
=
dateDay
.
getMonth
()
+
1
<
10
?
'0'
+
(
dateDay
.
getMonth
()
+
1
)
:
dateDay
.
getMonth
()
+
1
//获取当前月份的日期,不足10补0
const
d
=
dateDay
.
getDate
()
<
10
?
'0'
+
dateDay
.
getDate
()
:
dateDay
.
getDate
()
//获取当前几号,不足10补0
return
y
+
'-'
+
m
+
'-'
+
d
}
\ No newline at end of file
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论