Files
daywork/intern-log/src/views/LoginView.vue
T

116 lines
3.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { ref } from 'vue'
import Icon from '../components/Icon.vue'
import { createUser, login, type Session } from '../db/auth'
const emit = defineEmits<{ (e: 'login', s: Session): void }>()
const mode = ref<'login' | 'create'>('login')
const username = ref('')
const password = ref('')
const password2 = ref('')
const error = ref('')
const busy = ref(false)
function switchMode(m: 'login' | 'create') {
mode.value = m
error.value = ''
password2.value = ''
}
async function submit() {
if (busy.value) return
error.value = ''
busy.value = true
try {
let s: Session
if (mode.value === 'login') {
s = await login(username.value, password.value)
} else {
if (password.value.length < 6) {
error.value = '登录密码至少 6 位'
busy.value = false
return
}
if (password.value !== password2.value) {
error.value = '两次输入的密码不一致'
busy.value = false
return
}
s = await createUser(username.value, password.value)
}
emit('login', s)
} catch (e) {
error.value = e instanceof Error ? e.message : '操作失败'
}
busy.value = false
}
</script>
<template>
<div class="login-page">
<div class="card login-card">
<div class="login-brand">
<div class="brand-icon"><Icon name="calendar" :size="22" /></div>
<div class="login-title">实习工作日志</div>
<div class="muted login-sub">打卡 · 记录 · 总结 · 备忘录 · 密码库</div>
<div class="muted login-sub">数据保存在云端服务器,所有设备登录同一账号即可实时同步</div>
</div>
<div class="seg">
<button class="seg-btn" :class="{ active: mode === 'login' }" @click="switchMode('login')">登录</button>
<button class="seg-btn" :class="{ active: mode === 'create' }" @click="switchMode('create')">创建用户</button>
</div>
<input class="input" v-model="username" placeholder="用户名(2 到 20 个字符)" @keydown.enter="submit" />
<input type="password" class="input" v-model="password" :placeholder="mode === 'login' ? '登录密码' : '设置登录密码(至少 6 位)'" @keydown.enter="submit" />
<input v-if="mode === 'create'" type="password" class="input" v-model="password2" placeholder="再次输入密码" @keydown.enter="submit" />
<div v-if="error" class="form-error">{{ error }}</div>
<button class="btn btn-primary login-btn" :disabled="busy" @click="submit">
{{ mode === 'login' ? '登录' : '创建并进入' }}
</button>
<div class="muted login-note">
登录密码仅服务器保存哈希;本机保存加密的自动登录凭据,登录后无需重复输入
</div>
</div>
</div>
</template>
<style scoped>
.login-page {
min-height: 100vh;
min-height: 100dvh;
background: var(--bg-app);
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.login-card {
width: 400px;
max-width: 100%;
padding: 30px 28px;
display: flex;
flex-direction: column;
gap: 12px;
box-shadow: var(--shadow-float);
border-radius: var(--radius-lg);
}
.login-brand { text-align: center; margin-bottom: 6px; }
.brand-icon {
width: 46px;
height: 46px;
margin: 0 auto 10px;
border-radius: 12px;
background: var(--accent);
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
}
.login-title { font-size: 18px; font-weight: 600; color: var(--text-1); }
.login-sub { font-size: 12px; margin-top: 4px; line-height: 1.7; }
.form-error { color: var(--danger); font-size: 12px; }
.login-btn { margin-top: 2px; height: 36px; }
.login-note { font-size: 12px; text-align: center; line-height: 1.7; }
</style>