This commit is contained in:
parent
2baa76d893
commit
95280644a4
|
|
@ -458,7 +458,7 @@ const handleCreateOrder = async () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
// 获取跳转URL并打开支付页面
|
// 获取跳转URL并打开支付页面
|
||||||
const payUrl = res.payment_urls[0]
|
const payUrl = res.payment_urls[1]
|
||||||
if (payUrl) {
|
if (payUrl) {
|
||||||
if (isMobileDevice.value) {
|
if (isMobileDevice.value) {
|
||||||
// 移动端:直接跳转支付页面
|
// 移动端:直接跳转支付页面
|
||||||
|
|
|
||||||
|
|
@ -1,300 +1,335 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="user-card">
|
<div class="login-wrapper">
|
||||||
<UserHeader />
|
<div class="user-card">
|
||||||
<UserText :user-text="userText" @back="handleBack" />
|
<div class="brand">
|
||||||
<UserTabs v-model="activeTab" :hide-tab="hideTab" :tab-list="tabList" />
|
<img src="@/assets/images/logo.png" alt="logo" class="logo" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<el-form class="user-form" ref="loginFormRef" :model="loginForm" :rules="loginRules" @submit.prevent="handleLogin">
|
<div class="form-section">
|
||||||
<Transition name="form-switch" mode="out-in">
|
<h2 class="section-title">欢迎回来</h2>
|
||||||
<el-form-item v-if="activeTab === 'email'" key="form-email-item" prop="email">
|
<p class="section-tip">请输入您的账号信息</p>
|
||||||
<el-input v-model="loginForm.email" placeholder="请输入邮箱" clearable size="large" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item
|
<div class="login-tabs">
|
||||||
class="phone-item"
|
<div
|
||||||
prop="phone"
|
v-for="tab in tabList"
|
||||||
v-else-if="activeTab === 'phone'"
|
:key="tab.name"
|
||||||
key="form-phone-item"
|
:class="['tab-item', { active: activeTab === tab.name }]"
|
||||||
>
|
@click="activeTab = tab.name"
|
||||||
<el-select
|
|
||||||
v-model="loginForm.countryCode"
|
|
||||||
:teleported="false"
|
|
||||||
value-key="code"
|
|
||||||
placeholder="国家"
|
|
||||||
size="large"
|
|
||||||
>
|
>
|
||||||
<el-option
|
{{ tab.label }}
|
||||||
v-for="item in countryOptions"
|
</div>
|
||||||
:key="item.code"
|
</div>
|
||||||
:label="item.code"
|
|
||||||
:value="item.code"
|
|
||||||
>
|
|
||||||
<div class="country-option">
|
|
||||||
<span class="country-name">{{ item.name }}</span>
|
|
||||||
<span class="country-code">{{ item.code }}</span>
|
|
||||||
</div>
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
<el-input v-model="loginForm.phone" placeholder="请输入手机号" clearable size="large" @keyup.enter.prevent="handleLogin"/>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item v-else-if="activeTab === 'password'" key="form-password-item" prop="password">
|
<el-form class="form-body" ref="loginFormRef" :model="loginForm" :rules="rules" @submit.prevent="handleLogin">
|
||||||
<el-input
|
<el-form-item v-if="activeTab === 'email'" prop="email">
|
||||||
ref="passwordInputRef"
|
<el-input v-model="loginForm.email" placeholder="邮箱地址" size="large" clearable />
|
||||||
v-model="loginForm.password"
|
</el-form-item>
|
||||||
placeholder="请输入密码"
|
|
||||||
type="password"
|
<el-form-item class="phone-item" prop="phone" v-else>
|
||||||
show-password
|
<el-select class="country-select" v-model="loginForm.countryCode" :teleported="false" value-key="code" size="large">
|
||||||
clearable
|
<el-option v-for="item in countryOptions" :key="item.code" :label="item.code" :value="item.code" />
|
||||||
size="large"
|
</el-select>
|
||||||
/>
|
<el-input v-model="loginForm.phone" placeholder="手机号码" size="large" clearable @keyup.enter.prevent="handleLogin" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</Transition>
|
|
||||||
<el-form-item class="form-submit">
|
<el-form-item prop="password">
|
||||||
<el-button type="primary" @click="handleLogin" :loading="activeTab === 'password' && buttonLoading">登录</el-button>
|
<el-input v-model="loginForm.password" placeholder="登录密码" type="password" show-password size="large" @keyup.enter.prevent="handleLogin" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<span class="forgot-password" @click="handleForgotPassword">忘记密码?</span>
|
|
||||||
<span class="to-register" @click="handleRegister">没有账号?去注册</span>
|
<el-button type="primary" class="submit-btn" @click="handleLogin" :loading="buttonLoading">登 录</el-button>
|
||||||
</el-form>
|
|
||||||
|
<div class="link-row">
|
||||||
|
<span class="link" @click="handleForgotPassword">忘记密码?</span>
|
||||||
|
<span class="link" @click="handleRegister">没有账号?立即注册</span>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
name: 'Login'
|
|
||||||
})
|
|
||||||
// type类型
|
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
// 组件
|
|
||||||
import UserHeader from './components/Header.vue'
|
|
||||||
import UserText from './components/Text.vue'
|
|
||||||
import UserTabs from './components/Tabs.vue'
|
|
||||||
|
|
||||||
//公共方法/store/配置文件
|
|
||||||
import { useUserStore } from '@/stores/modules/user'
|
import { useUserStore } from '@/stores/modules/user'
|
||||||
import { useButtonLoading } from '@/composables/useLoading'
|
import { useButtonLoading } from '@/composables/useLoading'
|
||||||
import { setStorage, getStorage } from '@/utils/storage'
|
import { setStorage, getStorage } from '@/utils/storage'
|
||||||
import { md5Encrypt } from '@/utils/crypto'
|
|
||||||
|
|
||||||
//用户校验规则
|
|
||||||
import { countryOptions } from '@/views/user/config/mock'
|
import { countryOptions } from '@/views/user/config/mock'
|
||||||
import { passwordRules, emailRules, phoneRules, codeRules } from './config/rules'
|
import { passwordRules, emailRules, phoneRules } from './config/rules'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
// 按钮 loading
|
|
||||||
const { buttonLoading, startButtonLoading, stopButtonLoading } = useButtonLoading()
|
const { buttonLoading, startButtonLoading, stopButtonLoading } = useButtonLoading()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
//userText 实例
|
|
||||||
const userText = ref({
|
|
||||||
backText: '',
|
|
||||||
title: '',
|
|
||||||
text: '初次登录时,您的电子邮箱或手机号码将被用于注册。',
|
|
||||||
account: '',
|
|
||||||
})
|
|
||||||
|
|
||||||
//tabs 实例
|
|
||||||
const tabList = ref([
|
const tabList = ref([
|
||||||
{ label: '邮箱', name: 'email' },
|
{ label: '邮箱登录', name: 'email' },
|
||||||
{ label: '手机', name: 'phone' },
|
{ label: '手机登录', name: 'phone' },
|
||||||
])
|
])
|
||||||
const activeTab = ref<string>('email')
|
const activeTab = ref<string>('email')
|
||||||
const hideTab = ref<boolean>(false)
|
const loginFormRef = ref()
|
||||||
|
|
||||||
// login form 实例
|
|
||||||
const userStore = useUserStore()
|
|
||||||
const loginFormRef = ref<FormInstance>()
|
|
||||||
const passwordInputRef = ref()
|
|
||||||
const loginForm = ref({
|
const loginForm = ref({
|
||||||
email: '',
|
email: '',
|
||||||
countryCode: '+86',
|
countryCode: '+86',
|
||||||
phone: '',
|
phone: '',
|
||||||
password: '',
|
password: '',
|
||||||
code: '123456',
|
|
||||||
})
|
})
|
||||||
const loginRules = ref<FormRules>({
|
|
||||||
|
const rules = {
|
||||||
email: emailRules().email,
|
email: emailRules().email,
|
||||||
phone: phoneRules(loginForm.value).phone,
|
phone: phoneRules(loginForm.value).phone,
|
||||||
code: codeRules().code,
|
|
||||||
password: passwordRules(loginForm.value).password,
|
password: passwordRules(loginForm.value).password,
|
||||||
})
|
|
||||||
|
|
||||||
//方法
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成时间戳拼接6位随机数字的字符串
|
|
||||||
* @returns {string} 格式示例:1710688800000123456
|
|
||||||
*/
|
|
||||||
function generateTimestampWithRandomNum() {
|
|
||||||
// 1. 获取当前时间戳(毫秒级)
|
|
||||||
const timestamp = Date.now()
|
|
||||||
|
|
||||||
// 2. 生成6位随机数字(范围:000000 ~ 999999)
|
|
||||||
// Math.random()生成0~1的随机数,乘以1000000后取整,不足6位补0
|
|
||||||
const random6Num = Math.floor(Math.random() * 1000000)
|
|
||||||
.toString()
|
|
||||||
.padStart(6, '0')
|
|
||||||
|
|
||||||
// 3. 拼接并返回
|
|
||||||
return timestamp + random6Num
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 登录
|
function generateDeviceNo() {
|
||||||
const handleLogin = async () => {
|
return Date.now().toString() + Math.floor(Math.random() * 1000000).toString().padStart(6, '0')
|
||||||
console.log('触发登录');
|
}
|
||||||
|
|
||||||
|
async function handleLogin() {
|
||||||
if (!loginFormRef.value) return
|
if (!loginFormRef.value) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const currentTab = activeTab.value
|
await loginFormRef.value.validate()
|
||||||
//验证邮箱/手机号 → 切换到密码页
|
startButtonLoading()
|
||||||
if (currentTab === 'email' || currentTab === 'phone') {
|
|
||||||
//校验当前账号字段(email/phone)
|
try {
|
||||||
await loginFormRef.value.validateField(currentTab)
|
const deviceNo = getStorage('device_no', 'session') || generateDeviceNo()
|
||||||
//存储账号类型和账号值(方便后续登录取值)
|
await userStore.login({
|
||||||
const loginValue =
|
email: loginForm.value.email,
|
||||||
currentTab === 'phone'
|
mobile: loginForm.value.countryCode + loginForm.value.phone,
|
||||||
? loginForm.value.countryCode + loginForm.value[currentTab]
|
login_type: activeTab.value === 'email' ? 1 : 2,
|
||||||
: loginForm.value[currentTab]
|
password: loginForm.value.password,
|
||||||
setStorage('loginType', currentTab, 'session') // 存储账号类型(email/phone)
|
device_no: deviceNo+'',
|
||||||
setStorage('login', loginValue, 'session') // 存储账号值
|
})
|
||||||
//切换到密码页,更新提示
|
setStorage('device_no', deviceNo)
|
||||||
hideTab.value = true
|
} finally {
|
||||||
userText.value = {
|
stopButtonLoading()
|
||||||
backText: '返回',
|
|
||||||
title: '欢迎回来!',
|
|
||||||
text: '请输入您的登录密码',
|
|
||||||
account: loginValue,
|
|
||||||
}
|
|
||||||
activeTab.value = 'password'
|
|
||||||
|
|
||||||
if (currentTab === 'phone' && loginForm.value.email !== '') {
|
|
||||||
loginForm.value.email = ''
|
|
||||||
}
|
|
||||||
|
|
||||||
// 切换到密码页后自动聚焦密码输入框
|
|
||||||
setTimeout(() => {
|
|
||||||
passwordInputRef.value?.focus()
|
|
||||||
},400)
|
|
||||||
}
|
|
||||||
// 验证密码+验证码 → 执行登录
|
|
||||||
else if (currentTab === 'password') {
|
|
||||||
// 校验密码+验证码
|
|
||||||
await loginFormRef.value.validateField(['password', 'code'])
|
|
||||||
// 开启 loading
|
|
||||||
startButtonLoading()
|
|
||||||
try {
|
|
||||||
// 先从 storage 获取已存在的 device_no,如果没有则生成新的
|
|
||||||
const existingDeviceNo = getStorage('device_no', 'session')
|
|
||||||
console.log('existingDeviceNo:', existingDeviceNo);
|
|
||||||
const deviceNo = existingDeviceNo || generateTimestampWithRandomNum()
|
|
||||||
// 登录参数
|
|
||||||
const loginParams = {
|
|
||||||
email: loginForm.value.email,
|
|
||||||
mobile: loginForm.value.countryCode + loginForm.value.phone,
|
|
||||||
login_type: getStorage('loginType', 'session') === 'email' ? 1 : 2,
|
|
||||||
code: loginForm.value.code,
|
|
||||||
password: loginForm.value.password,
|
|
||||||
device_no: deviceNo+'',
|
|
||||||
}
|
|
||||||
await userStore.login(loginParams)
|
|
||||||
setStorage('device_no', deviceNo)
|
|
||||||
} finally {
|
|
||||||
// 关闭 loading
|
|
||||||
stopButtonLoading()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('表单校验失败:', error)
|
console.error('登录失败:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//返回登录页
|
function handleRegister() {
|
||||||
const handleBack = () => {
|
|
||||||
if (activeTab.value === 'password') {
|
|
||||||
// 从sessionStorage取账号类型(而非用password作为key)
|
|
||||||
const loginType = getStorage('loginType', 'session') || 'email'
|
|
||||||
// 清空密码、验证码字段,避免残留
|
|
||||||
loginForm.value.password = ''
|
|
||||||
loginForm.value.code = ''
|
|
||||||
// 清空表单校验提示
|
|
||||||
loginFormRef.value?.clearValidate(['password', 'code'])
|
|
||||||
// 重置文本和tab状态
|
|
||||||
hideTab.value = false
|
|
||||||
userText.value = {
|
|
||||||
backText: '',
|
|
||||||
title: '',
|
|
||||||
text: '初次登录时,您的电子邮箱或手机号码将被用于注册。',
|
|
||||||
account: '',
|
|
||||||
}
|
|
||||||
activeTab.value = loginType as string
|
|
||||||
} else {
|
|
||||||
// 非password页:仅重置为email(可选,也可保留当前tab)
|
|
||||||
activeTab.value = 'email'
|
|
||||||
// 清空当前账号字段和校验提示
|
|
||||||
loginForm.value.email = ''
|
|
||||||
loginForm.value.phone = ''
|
|
||||||
loginFormRef.value?.clearValidate(['email', 'phone'])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 跳转到注册页 - 清除登录状态
|
|
||||||
const handleRegister = () => {
|
|
||||||
userStore.clearUserInfo()
|
userStore.clearUserInfo()
|
||||||
router.push('/user/register')
|
router.push('/user/register')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 跳转到忘记密码页 - 清除登录状态
|
function handleForgotPassword() {
|
||||||
const handleForgotPassword = () => {
|
|
||||||
userStore.clearUserInfo()
|
userStore.clearUserInfo()
|
||||||
router.push('/user/forgot-password')
|
router.push('/user/forgot-password')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.user-form {
|
.login-wrapper {
|
||||||
|
min-height: 100vh;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background: radial-gradient(ellipse at center, #f0f7ff 0%, #e8f4fd 40%, #f5f9ff 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-card {
|
||||||
|
width: 600px;
|
||||||
|
padding: 0px 36px 40px 36px;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 18px;
|
||||||
|
box-shadow:
|
||||||
|
0 2px 4px rgba(0, 0, 0, 0.02),
|
||||||
|
0 6px 12px rgba(0, 0, 0, 0.03),
|
||||||
|
0 16px 32px rgba(0, 0, 0, 0.04);
|
||||||
|
|
||||||
|
.brand {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
// align-items: center;
|
||||||
|
// justify-content: center;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
padding-top: 8px;
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 160px;
|
||||||
|
height: auto;
|
||||||
|
// margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-name {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a365d;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section {
|
||||||
|
.section-title {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 26px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #0f172a;
|
||||||
|
margin: 0 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-tip {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #a0aec0;
|
||||||
|
margin: 0 0 28px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 0;
|
||||||
|
margin-bottom: 28px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.tab-item {
|
||||||
|
flex: 1;
|
||||||
|
padding: 12px 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #a0aec0;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 500;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 0;
|
||||||
|
height: 3px;
|
||||||
|
background: #1e40af;
|
||||||
|
border-radius: 3px;
|
||||||
|
transition: width 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: #1e40af;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
width: 44px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.active):hover {
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-body {
|
||||||
|
:deep(.el-form-item) {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-input__wrapper) {
|
||||||
|
padding: 8px 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
// border: 1.5px solid #e2e8f0;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
background: #fafbfc;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: #cbd5e1;
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-focus {
|
||||||
|
border-color: #1e40af;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0 0 0 3px rgba(30, 64, 175, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-input__inner) {
|
||||||
|
height: 36px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #1e293b;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: #b0b8c4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.phone-item {
|
.phone-item {
|
||||||
:deep(.el-form-item__content) {
|
:deep(.el-form-item__content) {
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-select {
|
:deep(.el-select) {
|
||||||
width: 120px;
|
width: 130px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
}
|
||||||
.country-option {
|
|
||||||
width: 120px;
|
:deep(.el-select--large .el-select__wrapper) {
|
||||||
display: flex;
|
border-radius: 10px;
|
||||||
justify-content: space-between;
|
border: 1px solid #e2e8f0;
|
||||||
}
|
background: #fafbfc;
|
||||||
|
box-shadow: none !important;
|
||||||
:deep(.el-select-dropdown__item) {
|
padding: 18px 12px;
|
||||||
padding: 0 16px 0 16px;
|
}
|
||||||
}
|
|
||||||
|
:deep(.el-select:hover .el-input__wrapper) {
|
||||||
|
border-color: #cbd5e1;
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-select.is-focus .el-input__wrapper) {
|
||||||
|
border-color: #1e40af !important;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0 0 0 3px rgba(30, 64, 175, 0.08) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.forgot-password {
|
.submit-btn {
|
||||||
font-size: 14px;
|
width: 100%;
|
||||||
color: #409eff;
|
height: 46px;
|
||||||
cursor: pointer;
|
font-size: 15px;
|
||||||
}
|
font-weight: 600;
|
||||||
|
letter-spacing: 3px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-top: 16px;
|
||||||
|
background: linear-gradient(135deg, #1e40af 0%, #2563eb 100%);
|
||||||
|
border: none;
|
||||||
|
box-shadow: 0 4px 14px rgba(30, 64, 175, 0.25);
|
||||||
|
transition: all 0.25s ease;
|
||||||
|
|
||||||
.form-submit {
|
&:hover {
|
||||||
margin-top: 18px;
|
background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%);
|
||||||
|
transform: scale(1.01);
|
||||||
|
box-shadow: 0 6px 18px rgba(30, 64, 175, 0.32);
|
||||||
|
}
|
||||||
|
|
||||||
:deep(.el-form-item__content) {
|
&:active {
|
||||||
width: 100%;
|
transform: scale(1);
|
||||||
|
box-shadow: 0 3px 10px rgba(30, 64, 175, 0.25);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.to-register {
|
|
||||||
|
.link-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: space-between;
|
||||||
cursor: pointer;
|
|
||||||
color: #409eff;
|
|
||||||
margin-top: 24px;
|
margin-top: 24px;
|
||||||
|
|
||||||
|
.link {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #1e40af;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #1e3a8a;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue