Files
ntu-awd-website/src/components/Login/LoginForm.vue
T
2025-04-17 02:04:35 +08:00

124 lines
3.3 KiB
Vue

<script setup>
import { ref, watch, computed, useTemplateRef } from 'vue';
import CAPTCHA from '../CAPTCHA.vue';
const emit = defineEmits(['login-submit']);
const username = ref('');
const password = ref('');
const captcha = useTemplateRef('captcha');
const captchaResponse = ref(null);
const captchaVerified = computed(() => {
return captchaResponse.value !== null;
});
const usernameError = ref('');
const passwordError = ref('');
function validateUsername() {
if (!username.value) {
usernameError.value = '使用者名稱為必填。';
} else if (username.value.length < 3) {
usernameError.value = '使用者名稱長度必須至少三個字元。';
} else {
usernameError.value = '';
}
}
function validatePassword() {
if (!password.value) {
passwordError.value = '密碼為必填。';
} else if (password.value.length < 8) {
passwordError.value = '密碼長度必須至少八個字元。';
} else {
passwordError.value = '';
}
}
watch(
() => username.value,
() => {
validateUsername();
}
);
watch(
() => password.value,
() => {
validatePassword();
}
);
const handleCaptchaVerified = (response) => {
captchaResponse.value = response;
};
const submit = () => {
validateUsername();
validatePassword();
if (usernameError.value || passwordError.value || !captchaVerified) {
return;
}
emit('login-submit', { username: username.value, password: password.value, captchaResponse: captchaResponse.value });
captcha.value.reset();
}
</script>
<template>
<form @submit.prevent="submit">
<div class="ts-box ts-content">
<div class="ts-header is-large is-center-aligned has-bottom-spaced">登入</div>
<div class="ts-wrap is-vertical">
<div class="ts-control is-wide">
<div class="label">使用者名稱</div>
<div class="content is-fluid">
<div class="ts-input" :class="{'is-negative': usernameError}">
<input name="username" type="text" placeholder="使用者名稱" v-model="username" />
</div>
<div class="ts-text is-small is-negative" v-if="usernameError">{{ usernameError }}</div>
</div>
</div>
<div class="ts-control is-wide">
<div class="label">密碼</div>
<div class="content is-fluid">
<div class="ts-input" :class="{'is-negative': passwordError}">
<input name="password" type="password" placeholder="密碼" v-model="password" />
</div>
<div class="ts-text is-small is-negative" v-if="passwordError">{{ passwordError }}</div>
</div>
</div>
</div>
<CAPTCHA
ref="captcha"
:hcaptchaSitekey="$hcaptchaSitekey"
:recaptchaSitekey="$recaptchaSitekey"
:turnstileSitekey="$turnstileSitekey"
@captchaVerified="handleCaptchaVerified"
/>
<div class="ts-wrap has-top-spaced is-end-aligned">
<button class="ts-button is-fluid" type="submit" :class="{
'is-disabled': username === '' || password === '' || usernameError !== '' || passwordError !== '' || !captchaVerified
}">登入</button>
</div>
</div>
</form>
</template>
<style scoped>
.ts-error {
color: red;
font-size: 0.8em;
}
.ts-control {
--label-width: 100px;
}
.ts-control .content.is-fluid {
max-width: 100%;
}
</style>