This commit is contained in:
Baobhan Sith
2025-04-19 09:09:38 +08:00
parent c18db0546a
commit 1b7a2abb5c
11 changed files with 643 additions and 168 deletions
+254
View File
@@ -0,0 +1,254 @@
<template>
<div class="login-view"> <!-- Use class from LoginView -->
<div class="login-form-container"> <!-- Use class from LoginView -->
<h2>{{ $t('setup.title') }}</h2>
<p class="text-center text-sm text-gray-600 dark:text-gray-400 mb-6"> <!-- Added margin bottom -->
{{ $t('setup.description') }}
</p>
<form @submit.prevent="handleSetup">
<div class="form-group"> <!-- Use class from LoginView -->
<label for="username">{{ $t('setup.username') }}:</label>
<input
id="username"
v-model="username"
name="username"
type="text"
required
:disabled="isLoading"
:placeholder="$t('setup.usernamePlaceholder')"
/>
</div>
<div class="form-group"> <!-- Use class from LoginView -->
<label for="password">{{ $t('setup.password') }}:</label>
<input
id="password"
v-model="password"
name="password"
type="password"
required
:disabled="isLoading"
:placeholder="$t('setup.passwordPlaceholder')"
/>
</div>
<div class="form-group"> <!-- Use class from LoginView -->
<label for="confirmPassword">{{ $t('setup.confirmPassword') }}:</label>
<input
id="confirmPassword"
v-model="confirmPassword"
name="confirmPassword"
type="password"
required
:disabled="isLoading"
:placeholder="$t('setup.confirmPasswordPlaceholder')"
/>
</div>
<!-- Use error-message class from LoginView -->
<div v-if="error" class="error-message">
{{ error }}
</div>
<!-- Use success-message styling similar to error -->
<div v-if="successMessage" class="success-message">
{{ successMessage }}
</div>
<button type="submit" :disabled="isLoading">
<span v-if="isLoading">{{ $t('setup.settingUp') }}</span>
<span v-else>{{ $t('setup.submitButton') }}</span>
</button>
</form>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import axios from 'axios';
import { useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useAuthStore } from '../stores/auth.store'; // *** 新增:导入 Auth Store ***
const { t } = useI18n();
const router = useRouter();
const authStore = useAuthStore(); // *** 新增:获取 Auth Store 实例 ***
const username = ref('');
const password = ref('');
const confirmPassword = ref('');
const isLoading = ref(false);
const error = ref<string | null>(null);
const successMessage = ref<string | null>(null);
const handleSetup = async () => {
error.value = null;
successMessage.value = null;
if (password.value !== confirmPassword.value) {
error.value = t('setup.error.passwordsDoNotMatch');
return;
}
if (!username.value || !password.value) {
error.value = t('setup.error.fieldsRequired');
return;
}
isLoading.value = true;
try {
// 确保调用正确的后端 API 端点
await axios.post('/api/v1/auth/setup', {
username: username.value,
password: password.value,
confirmPassword: confirmPassword.value
});
successMessage.value = t('setup.success');
// *** 新增:手动更新 needsSetup 状态 ***
authStore.needsSetup = false;
// *** 新增:重置认证状态,因为设置完成后需要重新登录 ***
authStore.isAuthenticated = false;
authStore.user = null;
// 禁用表单或按钮,防止重复提交
isLoading.value = true; // Keep loading state to disable button
// Redirect to login immediately after showing success message (removed setTimeout)
// The success message will be briefly visible before navigation.
router.push('/login');
} catch (err: any) {
console.error('Setup failed:', err);
if (err.response?.data?.message) {
// 尝试从后端响应中获取更具体的错误信息
error.value = err.response.data.message;
} else if (err.message) {
error.value = err.message;
} else {
error.value = t('setup.error.generic');
}
isLoading.value = false; // Re-enable button on error
}
// Removed finally block setting isLoading to false on success to keep button disabled
};
</script>
<!-- Copied styles from LoginView.vue -->
<style scoped>
.login-view {
display: flex;
justify-content: center;
align-items: center;
min-height: calc(100vh - 150px); /* Adjust based on header/footer height */
padding: 2rem;
/* Inherit background from body or set explicitly if needed */
background-color: var(--app-bg-color, #f8f9fa); /* Use CSS variable or fallback */
}
.login-form-container {
background-color: var(--card-bg-color, #fff); /* Use CSS variable or fallback */
color: var(--text-color, #333); /* Use CSS variable */
padding: 2rem 3rem;
border-radius: 8px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
border: 1px solid var(--border-color, #ccc); /* Use CSS variable */
width: 100%;
max-width: 400px;
}
/* Dark mode adjustments (assuming body has a dark class) */
.dark .login-form-container {
background-color: var(--card-bg-color-dark, #2d3748); /* Dark card background */
color: var(--text-color-dark, #f7fafc); /* Dark text */
border-color: var(--border-color-dark, #4a5568); /* Dark border */
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4);
}
h2 {
text-align: center;
margin-bottom: 1.5rem;
/* color: #333; */ /* Inherit from container */
}
.form-group {
margin-bottom: 1.5rem;
}
label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
/* color: #555; */ /* Inherit */
}
input[type="text"],
input[type="password"] {
width: 100%;
padding: 0.8rem;
border: 1px solid var(--border-color, #ccc); /* Use CSS variable */
border-radius: 4px;
box-sizing: border-box;
font-size: 1rem;
background-color: var(--input-bg-color, #fff); /* Use CSS variable */
color: var(--input-text-color, #333); /* Use CSS variable */
}
.dark input[type="text"],
.dark input[type="password"] {
border-color: var(--border-color-dark, #4a5568);
background-color: var(--input-bg-color-dark, #4a5568);
color: var(--input-text-color-dark, #f7fafc);
}
input:disabled {
background-color: var(--input-disabled-bg-color, #eee); /* Use CSS variable */
cursor: not-allowed;
opacity: 0.7;
}
.dark input:disabled {
background-color: var(--input-disabled-bg-color-dark, #4a5568);
}
.error-message {
color: #dc3545; /* Bootstrap danger color */
background-color: rgba(220, 53, 69, 0.1); /* Light red background */
border: 1px solid rgba(220, 53, 69, 0.2);
padding: 0.75rem 1.25rem;
margin-bottom: 1rem;
border-radius: 4px;
text-align: center;
font-size: 0.9rem;
}
.success-message {
color: #28a745; /* Bootstrap success color */
background-color: rgba(40, 167, 69, 0.1);
border: 1px solid rgba(40, 167, 69, 0.2);
padding: 0.75rem 1.25rem;
margin-bottom: 1rem;
border-radius: 4px;
text-align: center;
font-size: 0.9rem;
}
button[type="submit"] {
width: 100%;
padding: 0.8rem;
background-color: var(--primary-color, #007bff); /* Use CSS variable */
color: white;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.2s ease;
}
button[type="submit"]:hover:not(:disabled) {
background-color: var(--primary-hover-color, #0056b3); /* Use CSS variable */
}
button:disabled {
background-color: var(--button-disabled-bg-color, #a0cfff); /* Use CSS variable */
cursor: not-allowed;
opacity: 0.65;
}
</style>