提交 012e7f38 authored 作者: 王鹏飞's avatar 王鹏飞

chore: update

上级 f3c1a52c
......@@ -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' }
})
}
<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>
<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="attrs"></AppHeader>
<AppHeader v-bind="props"></AppHeader>
<section class="app-layout-container">
<router-view :key="$route.fullPath"></router-view>
</section>
......
......@@ -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;
......
......@@ -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) => {
......
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 }
})
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
......
......@@ -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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论