Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
P
project-online-fi
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
project-online-fi
Commits
012e7f38
提交
012e7f38
authored
11月 18, 2022
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore: update
上级
f3c1a52c
隐藏空白字符变更
内嵌
并排
正在显示
9 个修改的文件
包含
237 行增加
和
123 行删除
+237
-123
base.ts
src/api/base.ts
+31
-0
icon_user.png
src/assets/images/icon_user.png
+0
-0
Header.vue
src/components/layout/Header.vue
+132
-115
Index.vue
src/components/layout/Index.vue
+5
-2
Nav.vue
src/components/layout/Nav.vue
+1
-2
index.ts
src/router/index.ts
+1
-1
shop.ts
src/stores/shop.ts
+50
-0
user.ts
src/stores/user.ts
+14
-3
axios.ts
src/utils/axios.ts
+3
-0
没有找到文件。
src/api/base.ts
浏览文件 @
012e7f38
...
...
@@ -27,3 +27,34 @@ export function uploadFile(data: object) {
headers
:
{
'Content-Type'
:
'multipart/form-data'
}
})
}
// 获取已经购买的课程
export
function
getBuyShop
()
{
return
httpRequest
.
get
(
'https://learn-api.ezijing.com/api/lms-ep/v2/education/courses/my'
,
{
headers
:
{
tenant
:
'paa'
}
})
}
/**
* 发送验证码
*/
export
function
sendCode
(
data
:
any
)
{
return
httpRequest
.
post
(
'/api/usercenter/user/send-code'
,
data
,
{
headers
:
{
'Content-Type'
:
'multipart/form-data'
}
})
}
/**
* 检验验证码
*/
export
function
checkCode
(
params
:
any
)
{
return
httpRequest
.
get
(
'/api/usercenter/user/check-code'
,
{
params
})
}
/**
* 提交留咨信息
*/
export
function
postNes
(
data
:
any
)
{
return
httpRequest
.
post
(
'/api/enrollment/v1.0/applications'
,
data
,
{
headers
:
{
'Content-Type'
:
'multipart/form-data'
}
})
}
src/assets/images/icon_user.png
0 → 100644
浏览文件 @
012e7f38
1.7 KB
src/components/layout/Header.vue
浏览文件 @
012e7f38
<
script
setup
lang=
"ts"
>
import
{
ref
,
watch
,
computed
}
from
'vue'
import
{
useWindowScroll
}
from
'@vueuse/core'
import
{
useUserStore
}
from
'@/stores/user'
import
{
useRoute
}
from
'vue-router'
import
AppNav
from
'./Nav.vue'
import
{
ElMessage
}
from
'element-plus'
import
{
useDevice
}
from
'@/composables/useDevice'
const
userStore
=
useUserStore
()
interface
Props
{
fixed
?:
boolean
}
const
props
=
defineProps
<
Props
>
()
const
route
=
useRoute
()
const
user
=
useUserStore
()
const
LOGIN_URL
=
`
${
import
.
meta
.
env
.
VITE_LOGIN_URL
}
?rd=
${
encodeURIComponent
(
location
.
href
)}
`
const
REGISTER_URL
=
`
${
import
.
meta
.
env
.
VITE_REGISTER_URL
}
?rd=
${
encodeURIComponent
(
location
.
href
)}
`
user
.
getUser
()
// 菜单控制
const
menuVisible
=
ref
<
boolean
>
(
false
)
function
toggleMenu
()
{
menuVisible
.
value
=
!
menuVisible
.
value
}
watch
(
route
,
()
=>
{
menuVisible
.
value
=
false
})
const
classNames
=
computed
(()
=>
{
return
{
'has-menu'
:
menuVisible
.
value
,
'is-fixed'
:
props
.
fixed
,
'is-fixed'
:
props
.
fixed
&&
!
isScrolled
.
value
,
'is-scrolled'
:
isScrolled
.
value
}
})
...
...
@@ -43,147 +34,173 @@ const { y } = useWindowScroll()
const
isScrolled
=
computed
(()
=>
{
return
y
.
value
>
0
})
const
handleStudy
=
()
=>
{
if
(
userStore
.
courses
.
length
>
0
)
{
window
.
open
(
'https://paa-learning.ezijing.com'
)
}
else
{
ElMessage
.
warning
(
'请先购买课程,才能开始学习'
)
}
}
const
handleOrder
=
()
=>
{
window
.
open
(
'https://account-show.ezijing.com/payment'
)
}
const
{
mobile
}
=
useDevice
()
function
handleUser
()
{
if
(
user
.
isLogin
)
{
window
.
open
(
'https://account-show.ezijing.com/payment'
)
}
else
{
window
.
open
(
LOGIN_URL
)
}
}
</
script
>
<
template
>
<header
class=
"app-header"
:class=
"classNames"
ref=
"header"
>
<div
class=
"app-header-inner"
>
<div
class=
"app-header-left"
>
<div
class=
"logo"
>
<router-link
to=
"/"
>
<img
src=
"@/assets/images/logo.png"
v-if=
"isScrolled || !fixed"
/>
<img
src=
"@/assets/images/logo_white.png"
v-else
/>
</router-link>
</div>
</div>
<div
class=
"app-header-right"
>
<AppNav></AppNav>
<div
class=
"menu"
@
click=
"toggleMenu"
></div>
<router-link
to=
"/"
class=
"logo"
></router-link>
</div>
<div
class=
"app-header-right"
>
<AppNav></AppNav>
<div
class=
"app-header-right"
v-if=
"!mobile"
>
<div
class=
"study"
@
click=
"handleStudy"
v-if=
"user.isLogin"
>
立即学习
</div>
<template
v-if=
"user.isLogin"
>
你好,
{{
user
.
userName
}}
<div
class=
"app-header-logout"
@
click=
"handleLogout"
>
<img
src=
"https://webapp-pub.ezijing.com/project/saas/logout.png"
v-if=
"isScrolled || !fixed"
/>
<img
src=
"https://webapp-pub.ezijing.com/project_online/fi/logout_white.png"
v-else
/>
退出
</div>
<div
@
click=
"handleOrder"
style=
"cursor: pointer"
>
你好,
{{
user
.
userName
}}
</div>
<div
class=
"app-header-logout"
@
click=
"handleLogout"
>
退出
</div>
</
template
>
<
template
v-else
>
<a
:href=
"LOGIN_URL"
class=
"button-default"
>
登录
</a>
<a
class=
"button-primary"
:href=
"REGISTER_URL"
target=
"_blank"
>
注册
</a>
</
template
>
</div>
<div
class=
"app-header-right"
v-else
>
<div
class=
"app-header-user"
@
click=
"handleUser"
></div>
</div>
</div>
</header>
</template>
<
style
lang=
"scss"
>
.app-header
{
position
:
sticky
;
top
:
0
;
left
:
0
;
right
:
0
;
z-index
:
1000
;
&
.is-fixed
{
position
:
fixed
;
.is-pc
{
.app-header
{
position
:
sticky
;
top
:
0
;
left
:
0
;
right
:
0
;
color
:
#fff
;
background
:
linear-gradient
(
0deg
,
rgba
(
0
,
0
,
0
,
0
)
0%
,
rgba
(
0
,
0
,
0
,
0
.5
)
100%
);
.button-default
{
color
:
#fff
;
}
}
&
.is-scrolled
{
z-index
:
1000
;
color
:
#333
;
background
:
#fff
;
box-shadow
:
0px
0px
12px
rgba
(
0
,
0
,
0
,
0
.1
);
.button-default
{
color
:
#333
;
&
.is-fixed
{
position
:
fixed
;
left
:
0
;
right
:
0
;
color
:
#fff
;
background
:
linear-gradient
(
0deg
,
rgba
(
0
,
0
,
0
,
0
)
0%
,
rgba
(
0
,
0
,
0
,
0
.5
)
100%
);
.logo
{
background
:
url('@/assets/images/logo_white.png')
no-repeat
;
background-size
:
contain
;
}
.app-header-logout
{
background
:
url('https://webapp-pub.ezijing.com/project_online/fi/logout_white.png')
no-repeat
left
center
;
background-size
:
18px
;
}
.button-default
{
color
:
#fff
;
}
}
&
.is-scrolled
{
box-shadow
:
0px
0px
12px
rgba
(
0
,
0
,
0
,
0
.1
);
}
}
}
.app-header-inner
{
max-width
:
1200px
;
margin
:
0
auto
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
padding
:
0
.22rem
0
;
}
.app-header-left
{
flex
:
1
;
.logo
{
.app-header-inner
{
max-width
:
1200px
;
margin
:
0
auto
;
display
:
flex
;
align-items
:
center
;
img
{
height
:
0
.5rem
;
justify-content
:
space-between
;
padding
:
0
.22rem
0
;
}
.app-header-left
{
.logo
{
display
:
block
;
width
:
315px
;
height
:
50px
;
background
:
url('@/assets/images/logo.png')
no-repeat
;
background-size
:
contain
;
}
}
}
.app-header-right
{
.study
{
font-size
:
18px
;
line-height
:
50px
;
margin-right
:
30px
;
font-weight
:
400
;
cursor
:
pointer
;
.app-nav
{
flex
:
1
;
}
display
:
flex
;
.app-header-logout
{
// background: url('https://webapp-pub.ezijing.com/project/saas/logout.png') no-repeat left center;
padding-left
:
22px
;
margin-left
:
40px
;
cursor
:
pointer
;
.app-header-right
{
display
:
flex
;
img
{
width
:
18px
;
margin-right
:
10px
;
align-items
:
center
;
.study
{
font-size
:
18px
;
line-height
:
50px
;
margin-right
:
30px
;
font-weight
:
400
;
cursor
:
pointer
;
}
}
.button-default
{
min-width
:
72px
;
padding
:
0
10px
;
font-size
:
14px
;
line-height
:
24px
;
color
:
#333
;
text-align
:
center
;
border
:
1px
solid
#eaeaea
;
box-sizing
:
border-box
;
}
.button-primary
{
margin-left
:
10px
;
min-width
:
72px
;
padding
:
0
10px
;
font-size
:
14px
;
line-height
:
24px
;
color
:
#fff
;
text-align
:
center
;
background
:
var
(
--
main-color
);
box-sizing
:
border-box
;
.app-header-logout
{
background
:
url('https://webapp-pub.ezijing.com/project/saas/logout.png')
no-repeat
left
center
;
background-size
:
18px
;
padding-left
:
32px
;
margin-left
:
40px
;
cursor
:
pointer
;
display
:
flex
;
}
.button-default
{
min-width
:
72px
;
padding
:
0
10px
;
font-size
:
14px
;
line-height
:
24px
;
color
:
#333
;
text-align
:
center
;
border
:
1px
solid
#eaeaea
;
box-sizing
:
border-box
;
}
.button-primary
{
margin-left
:
10px
;
min-width
:
72px
;
padding
:
0
10px
;
font-size
:
14px
;
line-height
:
24px
;
color
:
#fff
;
text-align
:
center
;
background
:
var
(
--
main-color
);
box-sizing
:
border-box
;
}
}
}
.is-h5
{
.app-header-inner
{
padding
:
0
.32rem
0
.3rem
;
box-shadow
:
0
0
15px
rgb
(
0
0
0
/
14%
)
;
display
:
flex
;
padding
:
0
.4rem
0
.3rem
;
}
.menu
{
width
:
0
.36rem
;
height
:
0
.36rem
;
padding
:
5px
10px
;
background
:
url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAMAAABiM0N1AAAAh1BMVEUAAABAQEBgYGBVVVVgYGBmZmZoaGhgYGBgYGBlZWVlZWVjY2NjY2NmZmZkZGRlZWVkZGRmZmZjY2NmZmZlZWVmZmZmZmZlZWVmZmZlZWVmZmZmZmZlZWVlZWVmZmZmZmZlZWVmZmZlZWVlZWVmZmZmZmZmZmZlZWVmZmZmZmZlZWVmZmZmZmZgwHa9AAAALHRSTlMABAgMEBQbICgrMENIS09TVF9kZ2hrbG9zd3t/l5+jp6uvu8PD09fb3+vv86pHCLIAAACcSURBVBgZ7cHHFoJAEATAhkUx5wCsOYE6//99nvum/TxwmCo4107JuIqCaQaWXk3T5CCFqY4gB1PVIJWpziDhbppnDyxdRMWmA+eca6mwjIptFyx7mObVB4mmOoMcTFWDFKY6gqQ30zQ5WDIq4++qWYBzzrmvDeeKSQBLLqZpcpC1qU4ge1M1IKWpLiDhbpr3ACysdntBkcO5f/kAGgG16eBu+akAAAAASUVORK5CYII=')
no-repeat
center
;
background-size
:
0
.36rem
0
.36rem
;
cursor
:
pointer
;
.app-header-left
{
flex
:
1
;
.logo
{
display
:
block
;
width
:
3
.42rem
;
height
:
0
.54rem
;
background
:
url('@/assets/images/logo.png')
no-repeat
;
background-size
:
contain
;
}
}
.has-menu
.menu
{
background
:
url('https://webapp-pub.ezijing.com/www/h5/images/icon_close.png')
no-repeat
center
;
background-size
:
16px
16px
;
.app-header-right
{
display
:
flex
;
align-items
:
center
;
}
.app-header-user
{
width
:
0
.3rem
;
height
:
0
.3rem
;
background
:
url('@/assets/images/icon_user.png')
no-repeat
;
background-size
:
contain
;
cursor
:
pointer
;
}
}
</
style
>
src/components/layout/Index.vue
浏览文件 @
012e7f38
<
script
setup
lang=
"ts"
>
import
AppHeader
from
'./Header.vue'
import
AppFooter
from
'./Footer.vue'
const
attrs
=
useAttrs
()
interface
Props
{
fixed
?:
boolean
}
const
props
=
defineProps
<
Props
>
()
</
script
>
<
template
>
<div
class=
"app-layout"
>
<AppHeader
v-bind=
"
attr
s"
></AppHeader>
<AppHeader
v-bind=
"
prop
s"
></AppHeader>
<section
class=
"app-layout-container"
>
<router-view
:key=
"$route.fullPath"
></router-view>
</section>
...
...
src/components/layout/Nav.vue
浏览文件 @
012e7f38
...
...
@@ -24,10 +24,9 @@ const navList = [
height
:
50px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-
between
;
justify-content
:
space-
evenly
;
}
.app-menu
>
li
{
margin-right
:
80px
;
position
:
relative
;
>
.cell
{
font-size
:
18px
;
...
...
src/router/index.ts
浏览文件 @
012e7f38
...
...
@@ -10,7 +10,7 @@ const router = createRouter({
return
{
top
:
0
}
},
history
:
createWebHistory
(),
routes
:
[{
path
:
'/:pathMatch(.*)*'
,
redirect
:
'/
home
'
}]
routes
:
[{
path
:
'/:pathMatch(.*)*'
,
redirect
:
'/'
}]
})
// router.beforeEach((to, from, next) => {
...
...
src/stores/shop.ts
0 → 100644
浏览文件 @
012e7f38
import
{
defineStore
}
from
'pinia'
import
{
useUserStore
}
from
'./user'
interface
ShopFilter
{
label
:
string
value
:
string
courseList
:
any
}
type
ShopListItem
=
Record
<
string
,
any
>
export
const
useShopStore
=
defineStore
(
'shop'
,
()
=>
{
const
route
=
useRoute
()
const
userStore
=
useUserStore
()
// 筛选列表
const
filters
=
ref
<
ShopFilter
[]
>
((
window
as
any
).
SHOP
.
SHOP_FILTERS
)
// 商品列表
const
list
=
ref
<
ShopListItem
[]
>
((
window
as
any
).
SHOP
.
SHOP_LIST
)
// 计算后的商品列表,是否购买
const
shopList
=
computed
<
ShopListItem
[]
>
(()
=>
{
return
list
.
value
.
map
(
item
=>
{
const
isBuy
=
!!
userStore
.
courses
.
find
((
course
:
any
)
=>
course
.
course_id
===
item
.
course_id
)
return
{
...
item
,
isBuy
}
})
})
// 详情页面的单个商品
const
shopItem
=
computed
(()
=>
{
const
found
=
shopList
.
value
.
find
(
item
=>
item
.
id
===
route
.
params
.
id
)
if
(
found
)
{
found
.
course_list
=
found
.
child_ids
&&
found
.
child_ids
.
length
?
found
.
child_ids
.
map
((
id
:
string
)
=>
shopList
.
value
.
find
(
item
=>
item
.
id
===
id
))
:
shopList
.
value
.
filter
(
item
=>
item
.
child_ids
?.
includes
(
found
.
id
))
}
return
found
})
// 相关推荐商品列表
const
shopRelatedList
=
computed
(()
=>
{
return
shopList
.
value
.
filter
(
item
=>
item
.
category
!==
shopItem
.
value
?.
category
)
})
const
shopRelatedListOther
=
computed
(()
=>
{
return
shopList
.
value
.
filter
(
(
item
:
ShopListItem
)
=>
item
.
category
===
shopItem
.
value
?.
category
&&
item
.
id
!==
shopItem
.
value
?.
id
)
})
return
{
filters
,
list
,
shopList
,
shopItem
,
shopRelatedList
,
shopRelatedListOther
}
})
src/stores/user.ts
浏览文件 @
012e7f38
import
{
defineStore
}
from
'pinia'
import
{
getUser
,
logout
}
from
'@/api/base'
import
{
getUser
,
logout
,
getBuyShop
}
from
'@/api/base'
import
type
{
UserState
}
from
'@/types'
interface
State
{
user
:
UserState
|
null
courses
:
any
}
export
const
useUserStore
=
defineStore
({
id
:
'user'
,
state
:
():
State
=>
({
user
:
null
user
:
null
,
courses
:
[]
}),
getters
:
{
isLogin
:
state
=>
!!
state
.
user
,
userName
:
({
user
})
=>
{
if
(
!
user
)
return
''
return
user
.
realname
||
user
.
nickname
||
user
.
username
||
''
},
mobile
:
({
user
})
=>
{
if
(
!
user
)
return
''
return
user
.
mobile
}
},
actions
:
{
async
getUser
()
{
const
res
=
await
getUser
()
try
{
this
.
courses
=
await
getBuyShop
()
}
catch
(
error
)
{
console
.
log
(
error
)
}
this
.
user
=
res
.
data
},
async
logout
()
{
await
logout
()
this
.
user
=
null
...
...
src/utils/axios.ts
浏览文件 @
012e7f38
...
...
@@ -10,6 +10,9 @@ const httpRequest = axios.create({
httpRequest
.
interceptors
.
response
.
use
(
function
(
response
)
{
const
{
data
}
=
response
if
(
data
.
code
===
undefined
)
{
return
data
}
// 正常返回
if
(
data
.
code
===
0
)
{
return
data
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论