✨ add qq oauth2 support / start landing page
This commit is contained in:
@@ -16,4 +16,4 @@ VITE_TITLE_NAME='五味子云相册'
|
||||
VITE_APP_TOKEN_KEY='Bearer'
|
||||
|
||||
# the websocket url
|
||||
VITE_WEB_SOCKET_URL='ws://127.0.0.1:8080/api/ws/socket'
|
||||
VITE_WEB_SOCKET_URL='ws://127.0.0.1:8080/api/ws/gws'
|
||||
|
@@ -15,4 +15,4 @@ VITE_TITLE_NAME='五味子云相册'
|
||||
VITE_APP_TOKEN_KEY='Bearer'
|
||||
|
||||
# the websocket url
|
||||
VITE_WEB_SOCKET_URL='ws://127.0.0.1:8080/api/ws/socket'
|
||||
VITE_WEB_SOCKET_URL='ws://127.0.0.1:8080/api/ws/gws'
|
||||
|
3
components.d.ts
vendored
3
components.d.ts
vendored
@@ -7,6 +7,7 @@ export {}
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
3DCard: typeof import('./src/components/3DCard/3DCard.vue')['default']
|
||||
AButton: typeof import('ant-design-vue/es')['Button']
|
||||
AButtonGroup: typeof import('ant-design-vue/es')['ButtonGroup']
|
||||
ACard: typeof import('ant-design-vue/es')['Card']
|
||||
@@ -27,7 +28,9 @@ declare module 'vue' {
|
||||
ATimePicker: typeof import('ant-design-vue/es')['TimePicker']
|
||||
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
|
||||
BoxDog: typeof import('./src/components/BoxDog/BoxDog.vue')['default']
|
||||
Card3D: typeof import('./src/components/3DCard/Card3D.vue')['default']
|
||||
DynamicTitle: typeof import('./src/components/DynamicTitle/DynamicTitle.vue')['default']
|
||||
EffectsCard: typeof import('./src/components/EffectsCard/EffectsCard.vue')['default']
|
||||
ForgetPage: typeof import('./src/views/Forget/ForgetPage.vue')['default']
|
||||
LandingPage: typeof import('./src/views/Landing/LandingPage.vue')['default']
|
||||
LockOutlined: typeof import('@ant-design/icons-vue')['LockOutlined']
|
||||
|
@@ -17,6 +17,7 @@ export default [
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
// "no-unused-vars": "off",
|
||||
// "@typescript-eslint/no-unused-vars": ["off"],
|
||||
"vue/multi-word-component-names":"off",
|
||||
}
|
||||
}
|
||||
];
|
||||
|
22
src/App.vue
22
src/App.vue
@@ -1,7 +1,23 @@
|
||||
<template>
|
||||
<LayOut/>
|
||||
<AConfigProvider
|
||||
:locale="lang.lang === 'en' ? enUS : zhCN"
|
||||
:theme="app.themeConfig"
|
||||
>
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<transition name="animation" mode="out-in">
|
||||
<component :is="Component" :key="route.path"/>
|
||||
</transition>
|
||||
</router-view>
|
||||
</AConfigProvider>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import LayOut from "@/layout/default/DefaultLayout.vue";
|
||||
import enUS from 'ant-design-vue/es/locale/en_US';
|
||||
import zhCN from 'ant-design-vue/es/locale/zh_CN';
|
||||
import useStore from "@/store/index.ts";
|
||||
|
||||
const app = useStore().theme;
|
||||
const lang = useStore().lang;
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
|
@@ -3,9 +3,12 @@ import {service} from "@/utils/alova/service.ts";
|
||||
/**
|
||||
* Get Github OAuth URL
|
||||
*/
|
||||
export const getGithubUrl = () => {
|
||||
export const getGithubUrl = (state: string) => {
|
||||
return service.Get('/api/oauth/github/get_url',
|
||||
{
|
||||
params: {
|
||||
state: state
|
||||
},
|
||||
meta: {
|
||||
ignoreToken: true,
|
||||
},
|
||||
|
18
src/api/oauth/qq.ts
Normal file
18
src/api/oauth/qq.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import {service} from "@/utils/alova/service.ts";
|
||||
|
||||
export const getQQUrl = (state: string) => {
|
||||
return service.Get('/api/oauth/qq/get_url',
|
||||
{
|
||||
params: {
|
||||
state: state
|
||||
},
|
||||
meta: {
|
||||
ignoreToken: true,
|
||||
},
|
||||
cacheFor: {
|
||||
mode: "restore",
|
||||
expire: 1000 * 60 * 60 * 24 * 30 // 30 days
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
@@ -4,7 +4,7 @@ import {service} from "@/utils/alova/service.ts";
|
||||
* 生成客户端id
|
||||
*/
|
||||
export const generateClientId = () => {
|
||||
return service.Get('/api/oauth/generate_client_id',
|
||||
return service.Get('/api/oauth/wechat/generate_client_id',
|
||||
{
|
||||
meta: {
|
||||
ignoreToken: true,
|
||||
@@ -21,7 +21,7 @@ export const generateClientId = () => {
|
||||
* @param clientId
|
||||
*/
|
||||
export const generateQrCode = (clientId: string) => {
|
||||
return service.Get('/api/oauth/get_temp_qrcode',
|
||||
return service.Get('/api/oauth/wechat/get_temp_qrcode',
|
||||
{
|
||||
params: {
|
||||
client_id: clientId
|
||||
|
BIN
src/assets/images/logo-schisandra.png
Normal file
BIN
src/assets/images/logo-schisandra.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
1
src/assets/svgs/gitee.svg
Normal file
1
src/assets/svgs/gitee.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg t="1724030510306" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1626" width="200" height="200"><path d="M512 1024C230.4 1024 0 793.6 0 512S230.4 0 512 0s512 230.4 512 512-230.4 512-512 512z m259.2-569.6H480c-12.8 0-25.6 12.8-25.6 25.6v64c0 12.8 12.8 25.6 25.6 25.6h176c12.8 0 25.6 12.8 25.6 25.6V608c0 41.6-35.2 76.8-76.8 76.8h-240c-12.8 0-25.6-12.8-25.6-25.6V416c0-41.6 35.2-76.8 76.8-76.8h355.2c12.8 0 25.6-12.8 25.6-25.6v-64c0-12.8-12.8-25.6-25.6-25.6H416c-105.6 0-188.8 86.4-188.8 188.8V768c0 12.8 12.8 25.6 25.6 25.6h374.4c92.8 0 169.6-76.8 169.6-169.6V480c0-12.8-12.8-25.6-25.6-25.6z" fill="#888888" p-id="1627"></path></svg>
|
After Width: | Height: | Size: 683 B |
241
src/components/3DCard/Card3D.vue
Normal file
241
src/components/3DCard/Card3D.vue
Normal file
@@ -0,0 +1,241 @@
|
||||
<template>
|
||||
<div class="cards" style="transform: rotateX(-10.2deg) rotateY(-17.8deg);">
|
||||
<h3>Movies</h3>
|
||||
<h1>Popular</h1>
|
||||
<div class="card card__one">
|
||||
<div class="card__bg" style="background-position: -8.01px 4.59px;"></div>
|
||||
<img class="card__img" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/62105/3dr_mono.png"
|
||||
style="transform: translateX(17.8px) translateY(-10.2px);">
|
||||
<div class="card__text">
|
||||
<p class="card__title">Princess Mononoke</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card card__two">
|
||||
<div class="card__bg" style="background-position: -8.01px 4.59px;"></div>
|
||||
<img class="card__img" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/62105/3dr_chihiro.png"
|
||||
style="transform: translateX(17.8px) translateY(-10.2px);">
|
||||
<div class="card__text">
|
||||
<p class="card__title">Spirited Away</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card card__three">
|
||||
<div class="card__bg" style="background-position: -8.01px 4.59px;"></div>
|
||||
<img class="card__img" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/62105/3dr_howlcastle.png"
|
||||
style="transform: translateX(17.8px) translateY(-10.2px);">
|
||||
<div class="card__text">
|
||||
<p class="card__title">Howl's Moving Castle</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {onMounted} from "vue";
|
||||
|
||||
onMounted(() => {
|
||||
const cards: any = document.querySelector(".cards");
|
||||
const images: any = document.querySelectorAll(".card__img");
|
||||
const backgrounds: any = document.querySelectorAll(".card__bg");
|
||||
const range = 40;
|
||||
|
||||
// const calcValue = (a, b) => (((a * 100) / b) * (range / 100) -(range / 2)).toFixed(1);
|
||||
const calcValue = (a, b) => (a / b * range - range / 2).toFixed(1); // thanks @alice-mx
|
||||
|
||||
let timeout: any = null;
|
||||
document.addEventListener('mousemove', ({x, y}) => {
|
||||
if (timeout) {
|
||||
window.cancelAnimationFrame(timeout);
|
||||
}
|
||||
|
||||
timeout = window.requestAnimationFrame(() => {
|
||||
const yValue: any = calcValue(y, window.innerHeight);
|
||||
const xValue: any = calcValue(x, window.innerWidth);
|
||||
|
||||
cards.style.transform = `rotateX(${yValue}deg) rotateY(${xValue}deg)`;
|
||||
|
||||
[].forEach.call(images, (image: any) => {
|
||||
image.style.transform = `translateX(${-xValue}px) translateY(${yValue}px)`;
|
||||
});
|
||||
|
||||
[].forEach.call(backgrounds, (background: any) => {
|
||||
background.style.backgroundPosition = `${xValue * .45}px ${-yValue * .45}px`;
|
||||
});
|
||||
});
|
||||
}, false);
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
<style scoped>
|
||||
@import url("https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700,800");
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
align-items: center;
|
||||
background: #642B73;
|
||||
background: linear-gradient(to bottom, #C6426E, #642B73);
|
||||
display: flex;
|
||||
font-family: "Open Sans", sans;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
perspective: 1800px;
|
||||
text-align: center;
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #3e3e42;
|
||||
font-size: 32px;
|
||||
font-weight: 800;
|
||||
letter-spacing: -1px;
|
||||
margin-bottom: 30px;
|
||||
transform: translateZ(35px);
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #eb285d;
|
||||
font-size: 16px;
|
||||
margin-bottom: 6px;
|
||||
transform: translateZ(25px);
|
||||
}
|
||||
|
||||
.cards {
|
||||
background: #fff;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0px 10px 20px 20px rgba(0, 0, 0, 0.17);
|
||||
display: inline-block;
|
||||
padding: 30px 35px;
|
||||
perspective: 1800px;
|
||||
text-align: left;
|
||||
transform-origin: 50% 50%;
|
||||
transform-style: preserve-3d;
|
||||
transform: rotateX(11deg) rotateY(16.5deg);
|
||||
min-width: 595px;
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: 15px;
|
||||
box-shadow: 5px 5px 20px -5px rgba(0, 0, 0, 0.6);
|
||||
display: inline-block;
|
||||
height: 250px;
|
||||
overflow: hidden;
|
||||
perspective: 1200px;
|
||||
position: relative;
|
||||
transform-style: preserve-3d;
|
||||
transform: translatez(35px);
|
||||
transition: transform 200ms ease-out;
|
||||
width: 175px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.card:not(:last-child) {
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.card__img {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.card__bg {
|
||||
bottom: -50px;
|
||||
left: -50px;
|
||||
position: absolute;
|
||||
right: -50px;
|
||||
top: -50px;
|
||||
transform-origin: 50% 50%;
|
||||
transform: translateZ(-50px);
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.card__one .card__img {
|
||||
top: 14px;
|
||||
right: -10px;
|
||||
height: 110%;
|
||||
}
|
||||
|
||||
.card__one .card__bg {
|
||||
background: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/62105/3dr_monobg.jpg") center/cover no-repeat;
|
||||
}
|
||||
|
||||
.card__two .card__img {
|
||||
top: 25px;
|
||||
}
|
||||
|
||||
.card__two .card__bg {
|
||||
background: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/62105/3dr_spirited.jpg") center/cover no-repeat;
|
||||
}
|
||||
|
||||
.card__three .card__img {
|
||||
top: 5px;
|
||||
left: -4px;
|
||||
height: 110%;
|
||||
}
|
||||
|
||||
.card__three .card__bg {
|
||||
background: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/62105/3dr_howlbg.jpg") center/cover no-repeat;
|
||||
}
|
||||
|
||||
.card__text {
|
||||
align-items: center;
|
||||
background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.55) 100%);
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 70px;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.card__title {
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
padding: 0 10px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.notice {
|
||||
background: gold;
|
||||
border-top-left-radius: 6px;
|
||||
bottom: 0;
|
||||
font-family: monospace;
|
||||
font-size: 14px;
|
||||
padding: 8px 10px;
|
||||
position: absolute;
|
||||
right: -20px;
|
||||
}
|
||||
|
||||
.twitter__link {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: -10px;
|
||||
top: 12px;
|
||||
z-index: -1;
|
||||
background: #00aced;
|
||||
border-radius: 20px;
|
||||
height: 30px;
|
||||
text-decoration: none;
|
||||
padding-right: 10px;
|
||||
justify-content: space-between;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
width: 74px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.twitter__link:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.twitter__icon {
|
||||
height: 30px;
|
||||
}
|
||||
</style>
|
373
src/components/EffectsCard/EffectsCard.vue
Normal file
373
src/components/EffectsCard/EffectsCard.vue
Normal file
@@ -0,0 +1,373 @@
|
||||
<template>
|
||||
<div class="center">
|
||||
<h1>Daily UI 002: Credit Card Checkout</h1>
|
||||
<div class="wrapper">
|
||||
<button class="checkout">Checkout</button>
|
||||
<div class="card-wrap">
|
||||
<div class="card">
|
||||
<!--?xml version="1.0" encoding="utf-8"?-->
|
||||
<!-- Generator: Adobe Illustrator 19.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
|
||||
y="0px" viewBox="0 0 216.3 234.1" enable-background="new 0 0 216.3 234.1" xml:space="preserve">
|
||||
<g id="shadow">
|
||||
<g>
|
||||
<path fill="#5A488F" d="M178.1,211.7c14.8-2.1,23.9-5.1,23.9-8.3c0-6.6-37.8-11.9-84.4-11.9c-46.6,0-84.4,5.3-84.4,11.9
|
||||
c0,5.1,23,9.5,55.3,11.2c-10.5,2.1-16.7,4.7-16.7,7.6c0,6.6,32.4,11.9,72.3,11.9c39.9,0,72.3-5.3,72.3-11.9
|
||||
C216.3,217.7,200.8,213.7,178.1,211.7z"></path>
|
||||
</g>
|
||||
</g>
|
||||
<g id="back_hand">
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M43.4,127.7c-2.6-4.5-3.7-9-1.9-17.2c0.4-1.6-1-3.1-2.6-2.8c-6.9,1.2-6.2,14.1-6.2,14.1H4.8
|
||||
c-2,0-3.6,1.6-3.6,3.6v0.1c0,2,1.6,3.6,3.6,3.6h10.2v20.5c0,0.5,0.4,1,1,1H18h4.5h8.8c7.5,0,14-5.6,14.7-13.1
|
||||
C46.4,133.8,45.3,130.4,43.4,127.7z"></path>
|
||||
<g>
|
||||
<path fill="#DAEDF7" d="M32.7,125.9h-3.4c-2.3,0-4-1.9-3.8-4.2v0h7.2L32.7,125.9z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#665AA7" d="M18,130.2H4.8c-2.6,0-4.8-2.1-4.8-4.8c0-2.7,2.1-4.8,4.8-4.8h27.9c0.6,0,1.1,0.5,1.1,1.1
|
||||
s-0.5,1.1-1.1,1.1H4.8c-1.4,0-2.5,1.1-2.5,2.5c0,1.4,1.1,2.6,2.5,2.6H18c0.6,0,1.1,0.5,1.1,1.1S18.6,130.2,18,130.2z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#DAEDF7" d="M29.3,130.9c8.3-0.6,11.2,16.6,2,19.1c-3.3,0.6-2.8-0.8-2.8-0.8l0.6-2.6c0,0-2.7-2.4,0-7.4
|
||||
C27.9,136.2,29.3,133.6,29.3,130.9z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#665AA7" d="M31.7,151.6H18c-0.6,0-1.1-0.5-1.1-1.1s0.5-1.1,1.1-1.1h13.7c7.3,0,13.3-5.9,13.3-13.3
|
||||
c0-2.8-0.9-5.5-2.5-7.7c0,0,0-0.1-0.1-0.1c-2.6-4.4-4-9.2-2-18.1c0.1-0.4,0-0.8-0.3-1.1c-0.3-0.3-0.7-0.4-1-0.4
|
||||
c-3.6,0.6-5.5,7-5.3,17.1c0,0.6-0.5,1.1-1.1,1.2c-0.6,0-1.1-0.5-1.2-1.1c-0.3-11.7,2.3-18.6,7.2-19.4c1.1-0.2,2.2,0.2,3,1
|
||||
c0.8,0.8,1.1,2,0.9,3.2c-1.8,8.1-0.7,12.3,1.7,16.4c1.9,2.7,2.9,5.8,2.9,9C47.2,144.7,40.3,151.6,31.7,151.6z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#665AA7" d="M26.1,137.3h-8.5c-2.4,0-4.3-1.9-4.3-4.3v-0.8c0-2.4,1.9-4.3,4.3-4.3h8.5c2.4,0,4.3,1.9,4.3,4.3v0.8
|
||||
C30.4,135.4,28.5,137.3,26.1,137.3z M17.6,130.2c-1.1,0-2.1,0.9-2.1,2.1v0.8c0,1.1,0.9,2.1,2.1,2.1h8.5c1.1,0,2.1-0.9,2.1-2.1
|
||||
v-0.8c0-1.1-0.9-2.1-2.1-2.1H17.6z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#665AA7" d="M26.1,144.5h-8.5c-2.4,0-4.3-1.9-4.3-4.3v-0.8c0-2.4,1.9-4.3,4.3-4.3h8.5c2.4,0,4.3,1.9,4.3,4.3v0.8
|
||||
C30.4,142.5,28.5,144.5,26.1,144.5z M17.6,137.3c-1.1,0-2.1,0.9-2.1,2.1v0.8c0,1.1,0.9,2.1,2.1,2.1h8.5c1.1,0,2.1-0.9,2.1-2.1
|
||||
v-0.8c0-1.1-0.9-2.1-2.1-2.1H17.6z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#665AA7" d="M26.1,151.6h-8.5c-2.4,0-4.3-1.9-4.3-4.3v-0.8c0-2.4,1.9-4.3,4.3-4.3h8.5c2.4,0,4.3,1.9,4.3,4.3v0.8
|
||||
C30.4,149.7,28.5,151.6,26.1,151.6z M17.6,144.5c-1.1,0-2.1,0.9-2.1,2.1v0.8c0,1.1,0.9,2.1,2.1,2.1h8.5c1.1,0,2.1-0.9,2.1-2.1
|
||||
v-0.8c0-1.1-0.9-2.1-2.1-2.1H17.6z"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="card">
|
||||
<g>
|
||||
<path fill="#E02E92" d="M178.4,203.4H56.8c-4.8,0-8.6-3.9-8.6-8.6V8.6c0-4.8,3.9-8.6,8.6-8.6h121.5c4.8,0,8.6,3.9,8.6,8.6v186.2
|
||||
C187,199.6,183.1,203.4,178.4,203.4z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<rect x="144" fill="#363284" width="27.9" height="203.4"></rect>
|
||||
</g>
|
||||
</g>
|
||||
<g id="front_hand">
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M132.2,131.7c-2.6-4.5-3.7-9-1.9-17.2c0.4-1.6-1-3.1-2.6-2.8c-6.9,1.1-6.2,14.1-6.2,14.1H93.6
|
||||
c-2,0-3.6,1.6-3.6,3.6v0.1c0,2,1.6,3.6,3.6,3.6H104l0.4,21.4h16.2c7.9,0,14.4-6.4,14.4-14.4C135,137,134,134.1,132.2,131.7z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#DAEDF7" d="M125,125.7c0,0-0.6-2.5,0.8-6.9c0.6-1.9-2-2.9-3.3-0.6c0,0-0.9,1.5-0.9,7.3
|
||||
C124.5,125.7,125,125.7,125,125.7z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#665AA7" d="M120.6,155.6h-13.7c-2.6,0-4.7-2.1-4.7-4.7c0-1.4,0.6-2.7,1.6-3.6c-1-0.9-1.6-2.1-1.6-3.5
|
||||
c0-1.4,0.6-2.7,1.6-3.6c-1-0.9-1.6-2.1-1.6-3.5c0-0.9,0.3-1.8,0.7-2.5h-9.3c-2.6,0-4.8-2.1-4.8-4.8c0-2.7,2.1-4.8,4.8-4.8h26.7
|
||||
c0-4.1,0.8-13,7.2-14.1c1.1-0.2,2.2,0.2,3,1c0.8,0.8,1.1,2,0.9,3.2c-1.8,8.1-0.7,12.3,1.7,16.4c1.9,2.7,2.9,5.8,2.9,9
|
||||
C136.1,148.7,129.1,155.6,120.6,155.6z M108,147.3c0,0.6-0.5,1.1-1.1,1.1c-1.3,0-2.4,1.1-2.4,2.4c0,1.4,1.1,2.5,2.4,2.5h13.7
|
||||
c7.3,0,13.3-5.9,13.3-13.3c0-2.8-0.9-5.5-2.5-7.7c0,0,0-0.1-0.1-0.1c-2.6-4.4-4-9.2-2-18.1c0.1-0.4,0-0.8-0.3-1.1
|
||||
c-0.3-0.3-0.7-0.4-1-0.4c-4.9,0.8-5.3,9.6-5.3,11.9h1.6c0.6,0,1.1,0.5,1.1,1.1s-0.5,1.1-1.1,1.1H93.6c-1.4,0-2.5,1.1-2.5,2.5
|
||||
c0,1.4,1.1,2.6,2.5,2.6h13.2c0.6,0,1.1,0.5,1.1,1.1s-0.5,1.1-1.1,1.1c-1.3,0-2.4,1.1-2.4,2.4c0,1.2,0.8,2.2,2,2.4
|
||||
c0.5,0.1,0.9,0.6,0.9,1.1l0,0.1c0,0.5-0.4,1-0.9,1.1c-1.1,0.2-2,1.2-2,2.4c0,1.4,1.1,2.5,2.4,2.5
|
||||
C107.5,146.2,108,146.7,108,147.3z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M88.3,136"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="coins">
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#ED912F" d="M206.4,216c0,1.5-1,2.7-2.5,3c-5.6,1.1-20.3,3.2-38.2,3.2s-32.6-2-38.2-3.2c-1.4-0.3-2.5-1.6-2.5-3
|
||||
v-4.8h81.4V216z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<ellipse fill="#F9C441" cx="165.8" cy="211.2" rx="40.7" ry="3.9"></ellipse>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#ED912F" d="M206.4,207.8c0,1.5-1,2.7-2.5,3c-5.6,1.1-20.3,3.2-38.2,3.2s-32.6-2-38.2-3.2c-1.4-0.3-2.5-1.6-2.5-3
|
||||
V203h81.4V207.8z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<ellipse fill="#F9C441" cx="165.8" cy="203" rx="40.7" ry="3.9"></ellipse>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#ED912F" d="M213.7,200.5c0,1.5-1,2.7-2.5,3c-5.6,1.1-20.3,3.2-38.2,3.2s-32.6-2-38.2-3.2c-1.4-0.3-2.5-1.6-2.5-3
|
||||
v-4.8h81.4V200.5z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<ellipse fill="#F9C441" cx="173" cy="195.7" rx="40.7" ry="3.9"></ellipse>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#ED912F" d="M196.4,192.8c0,1.5-1,2.7-2.5,3c-5.6,1.1-20.3,3.2-38.2,3.2s-32.6-2-38.2-3.2c-1.4-0.3-2.5-1.6-2.5-3
|
||||
V188h81.4V192.8z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<ellipse fill="#F9C441" cx="155.7" cy="188" rx="40.7" ry="3.9"></ellipse>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<defs>
|
||||
<path id="SVGID_1_" d="M195.9,192.5V188c0-2.1-18.3-3.9-40.8-3.9s-40.8,1.7-40.8,3.9v4.8c0,1.5,1.3,2.7,2.8,3
|
||||
c2.9,0.6,7.9,1.4,15.1,2v2.7c0,0.1,0.1,0.2,0.1,0.3c-4.6,0.6-7.2,1.4-7.2,2.2v4.8c0,1,0.5,1.9,1.3,2.5c-0.8,0.3-1.3,0.6-1.3,1
|
||||
v4.8c0,1.5,0.9,2.7,2.3,3c5.6,1.1,20.3,3.2,38.1,3.2c17.9,0,32.3-2,38-3.2c1.4-0.3,2.2-1.6,2.2-3v-4.8c0-0.3-0.4-0.7-1.3-1
|
||||
c0.8-0.6,1.3-1.5,1.3-2.5v-3.5c2.6-0.3,3.5-0.6,4.7-0.8c1.4-0.3,2.4-1.6,2.4-3v-4.8C212.7,194.4,205.6,193.2,195.9,192.5z"></path>
|
||||
</defs>
|
||||
<clipPath id="SVGID_2_">
|
||||
<use xlink:href="#SVGID_1_" overflow="visible"></use>
|
||||
</clipPath>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<defs>
|
||||
<path id="SVGID_3_" d="M196.4,192.5V188c0-2.1-18.2-3.9-40.7-3.9c-0.1,0-0.2,0-0.3,0c-0.1,0-0.2,0-0.3,0c-5.6,0-11,0.1-15.8,0.3
|
||||
c3.5-3.5,6.1-6.3,7.6-8.1c0.9-1.1,1-2.8,0.1-3.9l-3-3.8c-1.3-1.7-16.7,8.3-34.3,22.3c-17.6,14-30.8,26.7-29.5,28.3l3,3.8
|
||||
c0.9,1.2,2.5,1.5,3.8,0.8c5.1-2.6,17.9-10.2,31.9-21.3c2.3-1.9,4.6-3.7,6.7-5.5c2,0.2,4.2,0.5,6.6,0.7v2.7c0,0.1,0.1,0.2,0.1,0.3
|
||||
c-4.6,0.6-7.2,1.4-7.2,2.2v4.8c0,1,0.5,1.9,1.3,2.5c-0.8,0.3-1.3,0.6-1.3,1v4.8c0,1.5,0.9,2.7,2.3,3c5.6,1.1,20.3,3.2,38.1,3.2
|
||||
c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0c17.9,0,32.6-2,38.2-3.2c1.4-0.3,2.5-1.6,2.5-3v-4.8c0-0.3-0.4-0.7-1.3-1
|
||||
c0.8-0.6,1.3-1.5,1.3-2.5v-3.5c1.9-0.3,3.6-0.6,4.7-0.8c1.4-0.3,2.5-1.6,2.5-3v-4.8C213.7,194.4,206.8,193.2,196.4,192.5z"></path>
|
||||
</defs>
|
||||
<clipPath id="SVGID_4_">
|
||||
<use xlink:href="#SVGID_3_" overflow="visible"></use>
|
||||
</clipPath>
|
||||
<polygon opacity="0.24" clip-path="url(#SVGID_4_)" fill="#ED1C24" points="146.8,176.4 150.7,184.1 173.6,191.5 173.4,198.3
|
||||
179.8,199.6 179.8,206.6 179.7,221.8 137.1,236.3 97.8,224.2 "></polygon>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#ED912F" d="M146.9,172.5c0.9,1.2,0.9,2.8-0.1,3.9c-3.7,4.4-14,15.1-28,26.2c-14,11.1-26.8,18.7-31.9,21.3
|
||||
c-1.3,0.7-2.9,0.3-3.8-0.8l-3-3.8l63.7-50.6L146.9,172.5z"></path>
|
||||
</g>
|
||||
<g>
|
||||
|
||||
<ellipse transform="matrix(0.7832 -0.6217 0.6217 0.7832 -96.3369 111.7049)" fill="#F9C441" cx="112"
|
||||
cy="194" rx="40.7" ry="3.9"></ellipse>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="mouth">
|
||||
<g>
|
||||
<path fill="#363284" d="M106.3,86.3c-1,0-1.9-0.1-2.9-0.4c-0.6-0.2-0.9-0.8-0.8-1.4c0.2-0.6,0.8-0.9,1.4-0.8
|
||||
c2.2,0.6,4.4,0.3,6.4-0.7c2-1.1,3.4-2.9,4-5.1c0.2-0.6,0.8-0.9,1.4-0.8c0.6,0.2,0.9,0.8,0.8,1.4C115.2,83.2,110.9,86.3,106.3,86.3
|
||||
z"></path>
|
||||
</g>
|
||||
</g>
|
||||
<g id="right_eye_wink">
|
||||
<g display="inline">
|
||||
<path fill="#363284" d="M116.4,40.9c-0.4,0-0.7-0.2-0.9-0.5c-0.3-0.5-0.2-1.2,0.3-1.6c2.6-1.7,9.5-5.2,17.8-0.4
|
||||
c0.5,0.3,0.7,1,0.4,1.5c-0.3,0.5-1,0.7-1.5,0.4c-6.9-4-12.6-1.5-15.4,0.4C116.8,40.9,116.6,40.9,116.4,40.9z"></path>
|
||||
</g>
|
||||
<g display="inline">
|
||||
<path fill="#363284" d="M130.7,55.9c-0.2,0-0.5-0.1-0.7-0.2c-4.1-3.1-11.8-2.8-11.9-2.8c-0.5,0-0.9-0.3-1.1-0.8
|
||||
c-0.2-0.5,0-1,0.4-1.3c0.3-0.2,8.1-5.8,14.3-3.1c0.6,0.3,0.8,0.9,0.6,1.5c-0.3,0.6-0.9,0.8-1.5,0.6c-2.8-1.3-6.3-0.2-8.8,1
|
||||
c2.9,0.3,6.7,1.1,9.4,3.1c0.5,0.4,0.6,1.1,0.2,1.6C131.4,55.8,131.1,55.9,130.7,55.9z"></path>
|
||||
</g>
|
||||
</g>
|
||||
<g id="right_eye">
|
||||
<g>
|
||||
<path fill="#363284" d="M133.5,53.6c-0.6-0.3-1.2-0.6-1.8-0.9c0.1-0.5,0.2-0.9,0.2-1.4c0-4-3.2-7.3-7.3-7.3c-4,0-7.3,3.2-7.3,7.3
|
||||
c0,0.6,0.1,1.2,0.2,1.7c-0.8,0.4-1.4,0.8-1.9,1.1c-0.5,0.3-0.7,1-0.3,1.6c0.2,0.3,0.6,0.5,0.9,0.5c0.2,0,0.4-0.1,0.6-0.2
|
||||
c2.8-1.9,8.5-4.4,15.4-0.4c0.5,0.3,1.2,0.1,1.5-0.4C134.2,54.6,134,54,133.5,53.6z"></path>
|
||||
<g>
|
||||
<path fill="#FFFFFF"
|
||||
d="M123,45.8c0.2,0.2,0.3,0.5,0.1,0.7s-0.4,0.2-0.6,0c-0.2-0.2-0.4-0.4-0.2-0.6S122.8,45.6,123,45.8z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M122.2,47.5c0,0.6-0.5,0.4-1.1,0.4c-0.6,0-1.1,0.2-1.1-0.4c0-0.6,0.5-1.1,1.1-1.1
|
||||
C121.7,46.5,122.2,46.9,122.2,47.5z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#363284" d="M116.4,39.2c-0.4,0-0.7-0.2-0.9-0.5c-0.3-0.5-0.2-1.2,0.3-1.6c2.6-1.7,9.5-5.2,17.8-0.4
|
||||
c0.5,0.3,0.7,1,0.4,1.5c-0.3,0.5-1,0.7-1.5,0.4c-6.9-4-12.6-1.5-15.4,0.4C116.8,39.2,116.6,39.2,116.4,39.2z"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="left_eye">
|
||||
<g>
|
||||
<path fill="#363284" d="M85.5,53.6c-0.6-0.3-1.2-0.6-1.8-0.9c0.1-0.5,0.2-0.9,0.2-1.4c0-4-3.2-7.3-7.3-7.3c-4,0-7.3,3.2-7.3,7.3
|
||||
c0,0.6,0.1,1.2,0.2,1.7c-0.8,0.4-1.4,0.8-1.9,1.1c-0.5,0.3-0.7,1-0.3,1.6c0.2,0.3,0.6,0.5,0.9,0.5c0.2,0,0.4-0.1,0.6-0.2
|
||||
c2.8-1.9,8.5-4.4,15.4-0.4c0.5,0.3,1.2,0.1,1.5-0.4C86.2,54.6,86,54,85.5,53.6z"></path>
|
||||
<g>
|
||||
<path fill="#FFFFFF"
|
||||
d="M75,45.8c0.2,0.2,0.3,0.5,0.1,0.7s-0.4,0.2-0.6,0c-0.2-0.2-0.4-0.4-0.2-0.6S74.8,45.6,75,45.8z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M74.2,47.5c0,0.6-0.5,0.4-1.1,0.4c-0.6,0-1.1,0.2-1.1-0.4c0-0.6,0.5-1.1,1.1-1.1
|
||||
C73.7,46.5,74.2,46.9,74.2,47.5z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#363284" d="M68.4,39.2c-0.4,0-0.7-0.2-0.9-0.5c-0.3-0.5-0.2-1.2,0.3-1.6c2.6-1.7,9.5-5.2,17.8-0.4
|
||||
c0.5,0.3,0.7,1,0.4,1.5c-0.3,0.5-1,0.7-1.5,0.4c-6.9-4-12.6-1.5-15.4,0.4C68.8,39.2,68.6,39.2,68.4,39.2z"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="sunglasses">
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#F9C441" d="M35.7,30v1.8c0,0.9,0.9,1.3,1.8,1.3h4.2v6.2c0,15.4,12.4,27.9,27.8,27.9l-0.1,0c12.6,0,23.2-8,26.6-19.6
|
||||
c0.7-2.5,2.7-4.5,5.2-5.1c3.7-0.8,7.2,1.5,8.2,4.9c3.3,11.3,13.2,19.2,25.2,19.8c16.2,0.7,29.1-12.7,29.1-28.9v-5.2h4.1
|
||||
c0.9,0,1.9-0.4,1.9-1.3V30c0-0.9-1-1.9-1.9-1.9H37.5C36.6,28.1,35.7,29.1,35.7,30z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<defs>
|
||||
<path id="SVGID_5_" d="M67.9,60.1c-11.7,0-22.2-8.9-22.2-20.8v-6.2h111v5.7c0,12.4-9.5,22.9-21.6,22.9l-0.1,0
|
||||
c-9.9-0.2-17.8-6.4-20.6-15.8c-1.5-5.3-6.3-9.1-11.8-9.1c-5.5,0-10.3,2.8-11.9,8.2c-2.8,9.5-11.4,15-21.4,15H67.9z"></path>
|
||||
</defs>
|
||||
<clipPath id="SVGID_6_">
|
||||
<use xlink:href="#SVGID_5_" overflow="visible"></use>
|
||||
</clipPath>
|
||||
<g clip-path="url(#SVGID_6_)">
|
||||
<path fill="#FFFFFF"
|
||||
d="M157.3,23.1h-9.2l-26.3,57h9.2L157.3,23.1z M145,23.1h-2.7l-26.3,57h2.7L145,23.1z"></path>
|
||||
</g>
|
||||
<g clip-path="url(#SVGID_6_)">
|
||||
<path fill="#FFFFFF"
|
||||
d="M88.4,23.1h-9.2l-26.3,57h9.2L88.4,23.1z M76.1,23.1h-2.7l-26.3,57h2.7L76.1,23.1z"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
|
||||
h1 {
|
||||
font-size: 1em;
|
||||
font-family: "Montserrat";
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
color: #b6d0e0;
|
||||
position: relative;
|
||||
margin-top: -15px;
|
||||
line-height: 15px;
|
||||
}
|
||||
|
||||
.center {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
width: 700px;
|
||||
flex-shrink: 0;
|
||||
background: white;
|
||||
overflow: hidden;
|
||||
height: 364px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1.5px 4px rgba(0, 0, 0, 0.24), 0 1.5px 6px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.card-wrap {
|
||||
width: 260px;
|
||||
float: right;
|
||||
background: #665aa7;
|
||||
padding: 50px;
|
||||
transform: scale(1.5) rotate(20deg);
|
||||
}
|
||||
|
||||
.card {
|
||||
transform: scale(0.75) rotate(-20deg);
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 150%;
|
||||
position: relative;
|
||||
right: 130px;
|
||||
top: 10px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
#sunglasses {
|
||||
transition: transform 0.15s;
|
||||
}
|
||||
|
||||
.checkout:hover ~ .card-wrap #sunglasses {
|
||||
transform: translateY(-40px);
|
||||
}
|
||||
|
||||
#right_eye_wink {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.checkout:active ~ .card-wrap #right_eye {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.checkout:active ~ .card-wrap #right_eye_wink {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#mouth {
|
||||
transition: transform 0.15s;
|
||||
}
|
||||
|
||||
.checkout:hover ~ .card-wrap #mouth {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
|
||||
#front_hand, #back_hand {
|
||||
transition: transform 0.03s;
|
||||
}
|
||||
|
||||
.checkout:active ~ .card-wrap #front_hand, .checkout:active ~ .card-wrap #back_hand {
|
||||
transform: translateX(10px);
|
||||
}
|
||||
|
||||
.checkout {
|
||||
outline: none;
|
||||
background: #665aa7;
|
||||
border: 0;
|
||||
color: white;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
left: 15%;
|
||||
transform: translateY(-50%);
|
||||
padding: 12px 16px;
|
||||
font-family: "Montserrat";
|
||||
text-transform: uppercase;
|
||||
font-size: 1.1em;
|
||||
letter-spacing: 0.1em;
|
||||
border-radius: 4px;
|
||||
transition: all 0.1s ease-out;
|
||||
box-shadow: 0 1.5px 4px rgba(0, 0, 0, 0.24), 0 1.5px 6px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.checkout:hover:not(:active) {
|
||||
background: #857bb9;
|
||||
}
|
||||
</style>
|
12
src/layout/Landing/Content/Content.vue
Normal file
12
src/layout/Landing/Content/Content.vue
Normal file
@@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<div style="display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 20px;">
|
||||
<Card3D/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
|
||||
import Card3D from "@/components/3DCard/Card3D.vue";
|
||||
</script>
|
||||
<style scoped>
|
||||
|
||||
</style>
|
11
src/layout/Landing/Footer/Footer.vue
Normal file
11
src/layout/Landing/Footer/Footer.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
<style scoped>
|
||||
|
||||
</style>
|
35
src/layout/Landing/Header/Header.vue
Normal file
35
src/layout/Landing/Header/Header.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<div class="landing-header">
|
||||
<AFlex :vertical="false" align-items="center" justify-content="space-between">
|
||||
<div class="logo">
|
||||
<img class="landing-header-logo" src="@/assets/svgs/logo-schisandra.svg" alt="logo">
|
||||
</div>
|
||||
</AFlex>
|
||||
<AFlex :vertical="false" justify="space-between">
|
||||
<div style="display: flex; align-items: center;justify-content: center;">
|
||||
<div class="toggle-box" style="margin-top: 20px;">
|
||||
<input @click="app.toggleDarkMode" v-model="isDarkMode" type="checkbox" name="checkbox1"
|
||||
id="toggle-box-checkbox">
|
||||
<label for="toggle-box-checkbox" class="toggle-box-label-left"></label>
|
||||
<label for="toggle-box-checkbox" class="toggle-box-label"></label>
|
||||
</div>
|
||||
<AButton @click="router.push('/login')" type="primary" size="large" style="margin-right: 10px;">立即进入
|
||||
</AButton>
|
||||
</div>
|
||||
</AFlex>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
|
||||
import router from "@/router/router.ts";
|
||||
import useStore from "@/store/index.ts";
|
||||
import {ref} from "vue";
|
||||
|
||||
const app = useStore().theme;
|
||||
const isDarkMode = ref<boolean>(app.darkMode === "dark");
|
||||
|
||||
</script>
|
||||
<style src="./index.scss" scoped>
|
||||
|
||||
</style>
|
118
src/layout/Landing/Header/index.scss
Normal file
118
src/layout/Landing/Header/index.scss
Normal file
@@ -0,0 +1,118 @@
|
||||
.landing-header {
|
||||
height: 100px;
|
||||
width: 80%;
|
||||
//background-color: #767779;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.landing-header-logo {
|
||||
display: inline-block;
|
||||
margin-right: 1rem;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.toggle-box-label-left:empty {
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
.toggle-box-label-left:before,
|
||||
.toggle-box-label-left:after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
/*transition*/
|
||||
-webkit-transition: 0.25s ease-in-out;
|
||||
-moz-transition: 0.25s ease-in-out;
|
||||
-o-transition: 0.25s ease-in-out;
|
||||
transition: 0.25s ease-in-out;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.toggle-box input[type=checkbox],
|
||||
.toggle-box input[type=checkbox]:active {
|
||||
position: absolute;
|
||||
top: -5000px;
|
||||
height: 0;
|
||||
width: 0;
|
||||
opacity: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.toggle-box label {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
padding: 0px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 14px;
|
||||
line-height: 16px;
|
||||
cursor: pointer;
|
||||
color: rgba(149, 149, 149, 0.51);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.toggle-box-label-left:before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
line-height: 34px;
|
||||
text-indent: 40px;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
margin: 4px;
|
||||
/*border-radius*/
|
||||
-webkit-border-radius: 100%;
|
||||
-moz-border-radius: 100%;
|
||||
border-radius: 100%;
|
||||
right: 26px;
|
||||
bottom: 0px;
|
||||
background: #FFB200;
|
||||
transform: rotate(-45deg);
|
||||
box-shadow: 0 0 10px white;
|
||||
}
|
||||
|
||||
.toggle-box-label-left:after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
height: 24px;
|
||||
/*border-radius*/
|
||||
-webkit-border-radius: 16px;
|
||||
-moz-border-radius: 16px;
|
||||
border-radius: 16px;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
vertical-align: middle;
|
||||
margin: 0 10px;
|
||||
border: 2px solid #FFB200;
|
||||
}
|
||||
|
||||
.toggle-box input[type=checkbox]:checked + .toggle-box-label-left:before {
|
||||
right: 17px;
|
||||
box-shadow: 5px 5px 0 0 #eee;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.toggle-box input[type=checkbox]:checked + .toggle-box-label-left:after {
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
border: 2px solid white;
|
||||
}
|
||||
|
||||
.toggle-box input[type=checkbox] + .toggle-box-label-left {
|
||||
color: rgba(250, 250, 250, 0.51);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.toggle-box input[type=checkbox]:checked + .toggle-box-label-left {
|
||||
color: rgba(149, 149, 149, 0.51);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.toggle-box input[type=checkbox]:checked + .toggle-box-label-left + .toggle-box-label {
|
||||
color: rgba(250, 250, 250, 0.51);
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
154
src/layout/Landing/index.vue
Normal file
154
src/layout/Landing/index.vue
Normal file
@@ -0,0 +1,154 @@
|
||||
<template>
|
||||
<AFlex :vertical="true" align="center" justify-content="center">
|
||||
<Header/>
|
||||
<Content/>
|
||||
<Footer/>
|
||||
<div class="area">
|
||||
<ul class="circles">
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
</ul>
|
||||
</div>
|
||||
</AFlex>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import Header from "@/layout/Landing/Header/Header.vue";
|
||||
import Footer from "@/layout/Landing/Footer/Footer.vue";
|
||||
import Content from "@/layout/Landing/Content/Content.vue";
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.area {
|
||||
background: #b9f187;
|
||||
background: -webkit-linear-gradient(to left, #b9f187, #90d952,#70c13a,#52a82e);
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
z-index: -1;
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
}
|
||||
|
||||
.circles {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.circles li {
|
||||
position: absolute;
|
||||
display: block;
|
||||
list-style: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
animation: animate 25s linear infinite;
|
||||
bottom: -150px;
|
||||
|
||||
}
|
||||
|
||||
.circles li:nth-child(1) {
|
||||
left: 25%;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
|
||||
.circles li:nth-child(2) {
|
||||
left: 10%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
animation-delay: 2s;
|
||||
animation-duration: 12s;
|
||||
}
|
||||
|
||||
.circles li:nth-child(3) {
|
||||
left: 70%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
animation-delay: 4s;
|
||||
}
|
||||
|
||||
.circles li:nth-child(4) {
|
||||
left: 40%;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
animation-delay: 0s;
|
||||
animation-duration: 18s;
|
||||
}
|
||||
|
||||
.circles li:nth-child(5) {
|
||||
left: 65%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
.circles li:nth-child(6) {
|
||||
left: 75%;
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
animation-delay: 3s;
|
||||
}
|
||||
|
||||
.circles li:nth-child(7) {
|
||||
left: 35%;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
animation-delay: 7s;
|
||||
}
|
||||
|
||||
.circles li:nth-child(8) {
|
||||
left: 50%;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
animation-delay: 15s;
|
||||
animation-duration: 45s;
|
||||
}
|
||||
|
||||
.circles li:nth-child(9) {
|
||||
left: 20%;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
animation-delay: 2s;
|
||||
animation-duration: 35s;
|
||||
}
|
||||
|
||||
.circles li:nth-child(10) {
|
||||
left: 85%;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
animation-delay: 0s;
|
||||
animation-duration: 11s;
|
||||
}
|
||||
|
||||
|
||||
@keyframes animate {
|
||||
|
||||
0% {
|
||||
transform: translateY(0) rotate(0deg);
|
||||
opacity: 1;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(-1000px) rotate(720deg);
|
||||
opacity: 0;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
@@ -1,23 +0,0 @@
|
||||
<template>
|
||||
<AConfigProvider
|
||||
:locale="lang.lang === 'en' ? enUS : zhCN"
|
||||
:theme="app.themeConfig"
|
||||
>
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<transition name="animation" mode="out-in">
|
||||
<component :is="Component" :key="route.path"/>
|
||||
</transition>
|
||||
</router-view>
|
||||
</AConfigProvider>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import enUS from 'ant-design-vue/es/locale/en_US';
|
||||
import zhCN from 'ant-design-vue/es/locale/zh_CN';
|
||||
import useStore from "@/store/index.ts";
|
||||
|
||||
const app = useStore().theme;
|
||||
const lang = useStore().lang;
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
@@ -23,7 +23,7 @@ export default {
|
||||
passwordRule: "密码要6~18位字符,且必须包含字母、数字和特殊符号!",
|
||||
phoneLoginAndRegister: "短信注册/登录",
|
||||
open: "请打开",
|
||||
scan: "扫码登录",
|
||||
scan: "扫码关注公众号",
|
||||
wechat: "微信",
|
||||
repassword: "确认密码",
|
||||
repasswordValidate: "请输入确认密码",
|
||||
|
@@ -1,20 +1,10 @@
|
||||
import {useAuthStore} from '@/store/modules/userStore.ts';
|
||||
import {useThemeStore} from "@/store/modules/themeStore.ts";
|
||||
import {langStore} from "@/store/modules/langStore.ts";
|
||||
import {useAuthSessionStore} from "@/store/modules/userSessionStore.ts";
|
||||
|
||||
export default function useStore() {
|
||||
// 是否自动登录 默认自动化登录
|
||||
function isAutoLogin() {
|
||||
const result: string | null = localStorage.getItem('auto_login');
|
||||
if (result) {
|
||||
return result === 'true';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return {
|
||||
user: isAutoLogin() ? useAuthStore() : useAuthSessionStore(), // 自动登录时使用 useAuthStore,否则使用 useAuthSessionStore
|
||||
user: useAuthStore(),
|
||||
theme: useThemeStore(),
|
||||
lang: langStore(),
|
||||
};
|
||||
|
@@ -1,27 +0,0 @@
|
||||
import {defineStore} from 'pinia';
|
||||
import {reactive} from 'vue';
|
||||
|
||||
|
||||
export const useAuthSessionStore = defineStore(
|
||||
'user',
|
||||
() => {
|
||||
const user: any = reactive({
|
||||
accessToken: '',
|
||||
uid: '',
|
||||
refreshToken: '',
|
||||
expiresAt: 0,
|
||||
});
|
||||
|
||||
return {
|
||||
user,
|
||||
};
|
||||
},
|
||||
{
|
||||
// 开启数据持久化
|
||||
persist: {
|
||||
key: 'user',
|
||||
storage: sessionStorage,
|
||||
paths: ['user'],
|
||||
}
|
||||
}
|
||||
);
|
2
src/types/user.d.ts
vendored
2
src/types/user.d.ts
vendored
@@ -1,11 +1,13 @@
|
||||
export interface AccountLogin {
|
||||
account?: string
|
||||
password?: string;
|
||||
auto_login?: boolean;
|
||||
}
|
||||
|
||||
export interface PhoneLogin {
|
||||
phone?: string
|
||||
captcha?: string;
|
||||
auto_login?: boolean;
|
||||
}
|
||||
|
||||
export interface ResetPassword {
|
||||
|
@@ -1,17 +1,11 @@
|
||||
<script lang="ts">
|
||||
import {defineComponent} from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: "LandingPage"
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h1>Welcome to our website!</h1>
|
||||
<LandingLayout/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import LandingLayout from "@/layout/Landing/index.vue";
|
||||
</script>
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
@@ -6,7 +6,13 @@
|
||||
router.push('/qrlogin')
|
||||
}" class="login-form-bottom-button" :icon="h(QrcodeOutlined)">{{ t("login.qrLogin") }}
|
||||
</AButton>
|
||||
<AButton @click="openGiteeUrl" class="login-form-bottom-button" :icon="h(QqOutlined)"></AButton>
|
||||
<AButton class="login-form-bottom-button" :icon="h(QqOutlined)"></AButton>
|
||||
<AButton @click="openGiteeUrl" class="login-form-bottom-button"
|
||||
style="display: flex; align-items: center;justify-content: center;">
|
||||
<template #icon>
|
||||
<img :src=gitee alt="gitee" class="gitee-icon" style="width: 16px; height: 16px;"/>
|
||||
</template>
|
||||
</AButton>
|
||||
<AButton @click="openGithubUrl" class="login-form-bottom-button" :icon="h(GithubOutlined)"></AButton>
|
||||
</AFlex>
|
||||
</div>
|
||||
@@ -20,17 +26,22 @@ import {getGithubUrl} from "@/api/oauth/github.ts";
|
||||
import {getGiteeUrl} from "@/api/oauth/gitee.ts";
|
||||
import useStore from "@/store";
|
||||
import {message} from "ant-design-vue";
|
||||
import gitee from "@/assets/svgs/gitee.svg";
|
||||
import {generateClientId} from "@/api/oauth/wechat.ts";
|
||||
import {getQQUrl} from "@/api/oauth/qq.ts";
|
||||
|
||||
const router = useRouter();
|
||||
const {t} = useI18n();
|
||||
const githubRedirectUrl = ref<string>('');
|
||||
const giteeRedirectUrl = ref<string>('');
|
||||
const qqRedirectUrl = ref<string>('');
|
||||
|
||||
/**
|
||||
* Get the redirect url of Github OAuth
|
||||
*/
|
||||
async function getGithubRedirectUrl() {
|
||||
const res: any = await getGithubUrl();
|
||||
const clientId: string = getLocalClientId() as string;
|
||||
const res: any = await getGithubUrl(clientId);
|
||||
if (res.code === 0 && res.data) {
|
||||
githubRedirectUrl.value = res.data;
|
||||
}
|
||||
@@ -46,6 +57,43 @@ async function getGiteeRedirectUrl() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the redirect url of QQ OAuth
|
||||
*/
|
||||
async function getQQRedirectUrl() {
|
||||
const clientId: string = getLocalClientId() as string;
|
||||
const res: any = await getQQUrl(clientId);
|
||||
if (res.code === 0 && res.data) {
|
||||
qqRedirectUrl.value = res.data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取client_id
|
||||
*/
|
||||
async function getClientId() {
|
||||
const id: string | null = localStorage.getItem('client_id');
|
||||
if (!id) {
|
||||
const res: any = await generateClientId();
|
||||
if (res.code === 0 && res.data) {
|
||||
localStorage.setItem('client_id', res.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本地client_id
|
||||
*/
|
||||
function getLocalClientId(): string | null {
|
||||
const clientID: string | null = localStorage.getItem('client_id');
|
||||
if (clientID) {
|
||||
return clientID;
|
||||
} else {
|
||||
getClientId();
|
||||
return localStorage.getItem('client_id');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the Github OAuth page in a new window
|
||||
*/
|
||||
@@ -106,6 +154,7 @@ const openGiteeUrl = () => {
|
||||
onMounted(() => {
|
||||
getGithubRedirectUrl();
|
||||
getGiteeRedirectUrl();
|
||||
getQQRedirectUrl();
|
||||
});
|
||||
</script>
|
||||
<style src="./index.scss" scoped>
|
||||
|
@@ -52,11 +52,9 @@
|
||||
</AFlex>
|
||||
|
||||
</AFormItem>
|
||||
<AFormItem>
|
||||
<AFormItem id="phone_login_auto" name="auto_login">
|
||||
<AFlex :vertical="false" justify="space-between">
|
||||
<ACheckbox @change="(e: any)=>{
|
||||
autoLoginChang(e.target.checked);
|
||||
}" v-model:checked="autoLoginChecked">{{ t("login.autoLogin") }}
|
||||
<ACheckbox v-model:checked="phoneLoginForm.auto_login">{{ t("login.autoLogin") }}
|
||||
</ACheckbox>
|
||||
</AFlex>
|
||||
|
||||
@@ -101,11 +99,9 @@
|
||||
</AInputPassword>
|
||||
</AFlex>
|
||||
</AFormItem>
|
||||
<AFormItem>
|
||||
<AFormItem id="account_login_auto" name="auto_login">
|
||||
<AFlex :vertical="false" justify="space-between">
|
||||
<ACheckbox v-model:checked="autoLoginChecked" @change="(e: any)=>{
|
||||
autoLoginChang(e.target.checked);
|
||||
}">{{ t("login.autoLogin") }}
|
||||
<ACheckbox v-model:checked="accountLoginForm.auto_login">{{ t("login.autoLogin") }}
|
||||
</ACheckbox>
|
||||
<a @click="()=>{
|
||||
router.push('/resetpass')
|
||||
@@ -162,7 +158,7 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {Rule} from "ant-design-vue/lib/form";
|
||||
import {onBeforeMount, onMounted, reactive, ref, UnwrapRef} from "vue";
|
||||
import {onMounted, reactive, ref, UnwrapRef} from "vue";
|
||||
import {AccountLogin, PhoneLogin} from "@/types/user";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import BoxDog from "@/components/BoxDog/BoxDog.vue";
|
||||
@@ -181,7 +177,6 @@ const showPhoneRotateCaptcha = ref<boolean>(false);
|
||||
const showAccountRotateCaptcha = ref<boolean>(false);
|
||||
const captchaData = reactive({angle: 0, image: "", thumb: "", key: ""});
|
||||
const captchaErrorCount = ref<number>(0);
|
||||
const autoLoginChecked = ref<boolean>(localStorage.getItem('auto_login') === 'true');
|
||||
const phoneLoginRotateEvent = {
|
||||
confirm: (angle: number) => {
|
||||
checkPhoneLoginCaptcha(angle);
|
||||
@@ -208,11 +203,13 @@ const accountLoginRotateEvent = {
|
||||
const accountLoginForm: UnwrapRef<AccountLogin> = reactive({
|
||||
account: '',
|
||||
password: '',
|
||||
auto_login: true,
|
||||
});
|
||||
// 手机登录表单数据
|
||||
const phoneLoginForm: UnwrapRef<PhoneLogin> = reactive({
|
||||
phone: '',
|
||||
captcha: '',
|
||||
auto_login: true,
|
||||
});
|
||||
// 表单验证提示
|
||||
const accountValidate = ref<string>(t('login.accountValidate'));
|
||||
@@ -442,21 +439,6 @@ async function sendMessageByPhone(): Promise<boolean> {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动登录
|
||||
* @param checkedValue
|
||||
*/
|
||||
async function autoLoginChang(checkedValue: boolean) {
|
||||
return localStorage.setItem('auto_login', String(checkedValue));
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
const autoLogin: string | null = localStorage.getItem('auto_login');
|
||||
if (!autoLogin) {
|
||||
localStorage.setItem('auto_login', 'true');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style src="./index.scss" scoped>
|
||||
@import "@/assets/styles/global.scss";
|
||||
|
@@ -1,7 +1,6 @@
|
||||
.login-main {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
//background-color: rgb(238, 255, 238);
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
/* 加载背景图 */
|
||||
|
@@ -15,7 +15,7 @@
|
||||
</span>
|
||||
<AQrcode
|
||||
class="qrlogin-card-qr"
|
||||
:size="230"
|
||||
:size="280"
|
||||
:error-level="'H'"
|
||||
:status="status"
|
||||
@refresh="() => {
|
||||
@@ -24,7 +24,6 @@
|
||||
:value=qrcode
|
||||
:icon="logo"
|
||||
/>
|
||||
<ACheckbox class="qrlogin-card-auto-login">{{ t("login.autoLogin") }}</ACheckbox>
|
||||
</AFlex>
|
||||
<QRLoginFooter/>
|
||||
<ATooltip placement="left">
|
||||
@@ -44,7 +43,7 @@ import {useI18n} from "vue-i18n";
|
||||
import BoxDog from "@/components/BoxDog/BoxDog.vue";
|
||||
import QRLoginFooter from "@/views/QRLogin/QRLoginFooter.vue";
|
||||
import {useRouter} from 'vue-router';
|
||||
import {closeWebsocket, generateClientId, generateQrCode} from "@/api/oauth/wechat.ts";
|
||||
import {generateClientId, generateQrCode} from "@/api/oauth/wechat.ts";
|
||||
import {onMounted, onUnmounted, ref} from "vue";
|
||||
import logo from "@/assets/svgs/logo-schisandra.svg";
|
||||
import useWebSocket from "@/utils/websocket/websocket.ts";
|
||||
@@ -80,30 +79,29 @@ async function getQrCode() {
|
||||
if (!clientId) {
|
||||
status.value = 'expired';
|
||||
await getClientId();
|
||||
return;
|
||||
}
|
||||
const res: any = await generateQrCode(clientId);
|
||||
if (res.code === 0 && res.data) {
|
||||
status.value = 'active';
|
||||
qrcode.value = res.data;
|
||||
localStorage.setItem('qr_code', res.data);
|
||||
await getQrCode();
|
||||
} else {
|
||||
status.value = 'expired';
|
||||
const res: any = await generateQrCode(clientId);
|
||||
if (res.code === 0 && res.data) {
|
||||
status.value = 'active';
|
||||
qrcode.value = res.data;
|
||||
} else {
|
||||
status.value = 'expired';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本地client_id
|
||||
*/
|
||||
function getLocalClientId(): string {
|
||||
function getLocalClientId(): string | null {
|
||||
const clientID: string | null = localStorage.getItem('client_id');
|
||||
if (clientID) {
|
||||
return clientID;
|
||||
} else {
|
||||
getClientId();
|
||||
return getLocalClientId();
|
||||
return localStorage.getItem('client_id');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const wsOptions = {
|
||||
@@ -113,13 +111,10 @@ const wsOptions = {
|
||||
const {open, close, on} = useWebSocket(wsOptions);
|
||||
|
||||
onMounted(async () => {
|
||||
await getClientId();
|
||||
await getQrCode();
|
||||
open();
|
||||
|
||||
// 注册消息接收处理函数
|
||||
on('message', (data: any) => {
|
||||
console.log(data);
|
||||
if (data.code === 0 && data.data) {
|
||||
const user = useStore().user;
|
||||
const {access_token, refresh_token, uid, expires_at} = data.data;
|
||||
@@ -134,9 +129,7 @@ onMounted(async () => {
|
||||
});
|
||||
|
||||
onUnmounted(async () => {
|
||||
await closeWebsocket(getLocalClientId());
|
||||
close(true);
|
||||
|
||||
});
|
||||
</script>
|
||||
<style src="./index.scss" scoped>
|
||||
|
@@ -6,7 +6,13 @@
|
||||
router.push('/login')
|
||||
}" class="qrlogin-form-bottom-button" :icon="h(TabletOutlined)">{{ t("login.phoneLoginAndRegister") }}
|
||||
</AButton>
|
||||
<AButton @click="openGiteeUrl" class="qrlogin-form-bottom-button" :icon="h(QqOutlined)"></AButton>
|
||||
<AButton class="qrlogin-form-bottom-button" :icon="h(QqOutlined)"></AButton>
|
||||
<AButton @click="openGiteeUrl" class="qrlogin-form-bottom-button"
|
||||
style="display: flex; align-items: center;justify-content: center;">
|
||||
<template #icon>
|
||||
<img :src=gitee alt="gitee" class="gitee-icon" style="width: 16px; height: 16px;"/>
|
||||
</template>
|
||||
</AButton>
|
||||
<AButton @click="openGithubUrl" class="qrlogin-form-bottom-button" :icon="h(GithubOutlined)"></AButton>
|
||||
</AFlex>
|
||||
</div>
|
||||
@@ -20,18 +26,23 @@ import {getGithubUrl} from "@/api/oauth/github.ts";
|
||||
import {getGiteeUrl} from "@/api/oauth/gitee.ts";
|
||||
import useStore from "@/store";
|
||||
import {message} from "ant-design-vue";
|
||||
import gitee from "@/assets/svgs/gitee.svg";
|
||||
import {generateClientId} from "@/api/oauth/wechat.ts";
|
||||
import {getQQUrl} from "@/api/oauth/qq.ts";
|
||||
|
||||
const router = useRouter();
|
||||
const {t} = useI18n();
|
||||
|
||||
const githubRedirectUrl = ref<string>('');
|
||||
const giteeRedirectUrl = ref<string>('');
|
||||
const qqRedirectUrl = ref<string>('');
|
||||
|
||||
/**
|
||||
* Get the redirect url of Github OAuth
|
||||
*/
|
||||
async function getGithubRedirectUrl() {
|
||||
const res: any = await getGithubUrl();
|
||||
const clientId: string = getLocalClientId() as string;
|
||||
const res: any = await getGithubUrl(clientId);
|
||||
if (res.code === 0 && res.data) {
|
||||
githubRedirectUrl.value = res.data;
|
||||
}
|
||||
@@ -47,6 +58,43 @@ async function getGiteeRedirectUrl() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取client_id
|
||||
*/
|
||||
async function getClientId() {
|
||||
const id: string | null = localStorage.getItem('client_id');
|
||||
if (!id) {
|
||||
const res: any = await generateClientId();
|
||||
if (res.code === 0 && res.data) {
|
||||
localStorage.setItem('client_id', res.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the redirect url of QQ OAuth
|
||||
*/
|
||||
async function getQQRedirectUrl() {
|
||||
const clientId: string = getLocalClientId() as string;
|
||||
const res: any = await getQQUrl(clientId);
|
||||
if (res.code === 0 && res.data) {
|
||||
qqRedirectUrl.value = res.data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本地client_id
|
||||
*/
|
||||
function getLocalClientId(): string | null {
|
||||
const clientID: string | null = localStorage.getItem('client_id');
|
||||
if (clientID) {
|
||||
return clientID;
|
||||
} else {
|
||||
getClientId();
|
||||
return localStorage.getItem('client_id');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the Github OAuth page in a new window
|
||||
*/
|
||||
@@ -107,6 +155,7 @@ const openGiteeUrl = () => {
|
||||
onMounted(() => {
|
||||
getGithubRedirectUrl();
|
||||
getGiteeRedirectUrl();
|
||||
getQQRedirectUrl();
|
||||
});
|
||||
</script>
|
||||
<style src="./index.scss" scoped>
|
||||
|
Reference in New Issue
Block a user