feat: 登录页面

This commit is contained in:
2026-06-08 16:09:57 +08:00
parent fb60a6b7ee
commit 391def3c92
15 changed files with 754 additions and 130 deletions

View File

@@ -1,81 +1,29 @@
<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router'
</script>
<template>
<header>
<img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
<div class="wrapper bg-amber-400">
<nav>
<RouterLink to="/">Home</RouterLink>
</nav>
</div>
</header>
<RouterView />
<NConfigProvider
:locale="zhCN"
:date-locale="dateZhCN"
:theme="lightTheme"
:theme-overrides="themeOverrides"
class="h-full"
>
<NNotificationProvider>
<NMessageProvider>
<router-view />
</NMessageProvider>
</NNotificationProvider>
</NConfigProvider>
</template>
<style scoped>
header {
line-height: 1.5;
max-height: 100vh;
}
<script setup lang="ts">
import { RouterView } from 'vue-router'
import { zhCN, dateZhCN, lightTheme, useThemeVars, type GlobalThemeOverrides } from 'naive-ui'
.logo {
display: block;
margin: 0 auto 2rem;
}
nav {
width: 100%;
font-size: 12px;
text-align: center;
margin-top: 2rem;
}
nav a.router-link-exact-active {
color: var(--color-text);
}
nav a.router-link-exact-active:hover {
background-color: transparent;
}
nav a {
display: inline-block;
padding: 0 1rem;
border-left: 1px solid var(--color-border);
}
nav a:first-of-type {
border: 0;
}
@media (min-width: 1024px) {
header {
display: flex;
place-items: center;
padding-right: calc(var(--section-gap) / 2);
}
.logo {
margin: 0 2rem 0 0;
}
header .wrapper {
display: flex;
place-items: flex-start;
flex-wrap: wrap;
}
nav {
text-align: left;
margin-left: -1rem;
font-size: 1rem;
padding: 1rem 0;
margin-top: 1rem;
const themeOverrides: GlobalThemeOverrides = {
common: {
primaryColor: '#2080F0',
primaryColorHover: '#4098fc',
primaryColorPressed: '#1060c9',
primaryColorSuppl: '#4098fc'
}
}
</style>
</script>

View File

@@ -1,10 +1,5 @@
@import 'tailwindcss';
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
font-weight: normal;
}

View File

@@ -0,0 +1,2 @@
import './tailwind.css'
import './base.css'

View File

@@ -0,0 +1,14 @@
@import 'tailwindcss';
@utility flex-center {
display: flex;
align-items: center;
justify-content: center;
}
@utility flex-col-center {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}

View File

@@ -1,9 +1,43 @@
<template>
<div class="flex min-h-lvh flex-1 overflow-x-hidden select-none">
<router-view></router-view>
<div class="relative flex-center w-full">
<div class="login-background absolute top-0 left-0 size-full"></div>
<div
class="flex-col-center relative bg-white rounded-3xl pb-10 px-6 py-10 md:w-2/3 lg:w-1/2 xl:w-[36%]"
>
<RouterView v-slot="{ Component, route }">
<Transition appear mode="out-in" name="slide-right">
<KeepAlive :include="['Login']">
<component
:is="Component"
:key="route.fullPath"
class="side-content mt-6 w-full sm:mx-auto md:max-w-md"
/>
</KeepAlive>
</Transition>
</RouterView>
<div class="absolute bottom-3 flex text-center text-xs">
<span style="color: #71717a">Copyright © 2024</span>
<a href="javascript:void(0)" class="ml-2" style="color: #2080f0">MarchGlow</a>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import { useThemeVars } from 'naive-ui'
const themeVars = useThemeVars()
</script>
<style scoped></style>
<style scoped>
.login-background {
background: linear-gradient(
154deg,
#07070915 30%,
color-mix(in srgb, v-bind(themeVars.primaryColor) 30%, transparent) 48%,
#07070915 64%
);
filter: blur(100px);
}
</style>

View File

@@ -1,4 +1,4 @@
import './assets/style/base.css'
import './assets/style'
import { createApp } from 'vue'
import { initPinia } from './stores'

View File

@@ -1,12 +0,0 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})

View File

@@ -1,2 +1,2 @@
export * from './initPinia.ts'
export * from './counter.ts'
export * from './modules'

View File

@@ -0,0 +1,37 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
/** 账户信息 */
export interface AccountState {
/** 账户ID */
id: string
/** 用户名 */
username: string
/** 年龄 */
age?: number
/** 性别 */
sex?: string
/** 手机号 */
phone?: string
/** 邮箱 */
email?: string
/** 头像 */
avatar?: string
/** 生日 */
birthday?: string
}
export const useAccountStore = defineStore(
'account',
() => {
const accountInfo = ref<AccountState>()
const token = ref('')
return { accountInfo, token }
},
{
persist: {
pick: ['accountInfo', 'token']
}
}
)

View File

@@ -0,0 +1 @@
export * from './account.ts'

View File

@@ -1,7 +1,94 @@
<template>
<div class="h-40 w-40 bg-amber-200"></div>
<div class="flex-col-center">
<div class="w-full">
<h2 class="text-3xl/9 mb-3 font-bold lg:text-4xl">欢迎回来 👋🏻</h2>
<p>
<span style="color: #71717a">登录账号以进入对战</span>
</p>
</div>
<n-form
ref="formRef"
:model="loginModel"
:rules="rules"
:show-label="false"
class="w-full mt-10"
>
<n-form-item path="username">
<n-input v-model:value="loginModel.username" placeholder="请输入账号" :maxlength="20" />
</n-form-item>
<n-form-item path="password">
<n-input
v-model:value="loginModel.password"
type="password"
show-password-on="mousedown"
placeholder="密码"
:maxlength="20"
/>
</n-form-item>
<n-form-item>
<div class="flex flex-1 items-center justify-between">
<n-checkbox>记住账号</n-checkbox>
<a href="javascript:void(0)" style="color: #2080f0">忘记密码</a>
</div>
</n-form-item>
<n-form-item>
<n-button :loading="loginLoading" style="width: 100%" type="primary" @click="userLoginFun"
>登录</n-button
>
</n-form-item>
<n-form-item>
<div class="flex-center flex-1">
<span>没有账号</span>
<router-link to="/auth/register" style="color: #2080f0">注册</router-link>
</div>
</n-form-item>
</n-form>
</div>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import { reactive, ref, useTemplateRef } from 'vue'
import type { FormItemRule, FormRules, FormInst } from 'naive-ui'
import { useAccountStore } from '@/stores'
const accountStore = useAccountStore()
const formRef = useTemplateRef<FormInst>('formRef')
const loginModel = reactive({
username: '',
password: ''
})
const loginLoading = ref(false)
const rules: FormRules = {
username: [
{
required: true,
message: '请输入登陆账号',
trigger: ['blur']
}
],
password: [
{
required: true,
message: '请输入登陆密码',
trigger: ['blur']
}
]
}
const userLoginFun = () => {
formRef.value?.validate((errors) => {
if (!errors) {
loginLoading.value = true
console.log('登录成功')
// TODO 登录方法
accountStore.token = '123456'
setTimeout(() => {
loginLoading.value = false
}, 1000)
}
})
}
</script>
<style scoped></style>