태그를 관리용/일반용으로 분리하고 관리자 드래그 정렬을 추가.
댓글/회원/관리자 인증·프로필 흐름 보완과 관련 마이그레이션 및 문서를 함께 반영해 운영 동선을 안정화. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -6,6 +6,7 @@ definePageMeta({
|
||||
const currentStep = ref(1)
|
||||
const isSubmitting = ref(false)
|
||||
const signupCompleted = ref(false)
|
||||
const createdAdmin = ref(false)
|
||||
const statusMessage = ref('')
|
||||
const submitErrorMessage = ref('')
|
||||
const { data: siteSettings } = await useFetch('/api/site-settings', {
|
||||
@@ -14,6 +15,12 @@ const { data: siteSettings } = await useFetch('/api/site-settings', {
|
||||
description: 'Configure your Self Host AFFiNE with a few simple settings.'
|
||||
})
|
||||
})
|
||||
const { data: bootstrapStatus } = await useFetch('/api/auth/bootstrap-status', {
|
||||
default: () => ({
|
||||
hasUsers: true,
|
||||
needsAdminSetup: false
|
||||
})
|
||||
})
|
||||
|
||||
const form = reactive({
|
||||
username: '',
|
||||
@@ -32,8 +39,13 @@ const errors = reactive({
|
||||
const showSignupPassword = ref(false)
|
||||
const showSignupPasswordConfirm = ref(false)
|
||||
|
||||
const isAdminBootstrapMode = computed(() => Boolean(bootstrapStatus.value?.needsAdminSetup))
|
||||
const welcomeTitle = computed(() => `Welcome to ${siteSettings.value?.title || 'AFFiNE'}`)
|
||||
const welcomeDescription = computed(() => siteSettings.value?.description || 'Configure your Self Host AFFiNE with a few simple settings.')
|
||||
const stepTwoTitle = computed(() => (isAdminBootstrapMode.value ? '관리자 등록' : '회원 가입'))
|
||||
const stepTwoDescription = computed(() => (isAdminBootstrapMode.value
|
||||
? '첫 번째 사용자이므로 소유자 권한이 부여됩니다. 관리 작업 및 사용자 생성이 가능합니다.'
|
||||
: '서비스 이용을 위한 회원 정보를 입력해 주세요.'))
|
||||
|
||||
/**
|
||||
* 필드 에러 메시지를 초기화한다.
|
||||
@@ -107,7 +119,7 @@ const goNextStep = async () => {
|
||||
isSubmitting.value = true
|
||||
|
||||
try {
|
||||
await $fetch('/api/auth/signup', {
|
||||
const signupResult = await $fetch('/api/auth/signup', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
username: form.username.trim(),
|
||||
@@ -115,11 +127,14 @@ const goNextStep = async () => {
|
||||
password: form.password
|
||||
}
|
||||
})
|
||||
createdAdmin.value = Boolean(signupResult?.isAdmin)
|
||||
|
||||
signupCompleted.value = true
|
||||
currentStep.value = 3
|
||||
statusMessage.value = '회원가입이 완료되었습니다. 잠시 후 홈으로 이동합니다.'
|
||||
await navigateTo('/')
|
||||
statusMessage.value = createdAdmin.value
|
||||
? '관리자 등록이 완료되었습니다. 관리자 화면으로 이동합니다.'
|
||||
: '회원가입이 완료되었습니다. 잠시 후 홈으로 이동합니다.'
|
||||
await navigateTo(createdAdmin.value ? '/admin' : '/')
|
||||
} catch (error) {
|
||||
submitErrorMessage.value = error?.data?.message || '회원가입에 실패했습니다.'
|
||||
} finally {
|
||||
@@ -157,15 +172,15 @@ const goPreviousStep = () => {
|
||||
|
||||
<template v-else-if="currentStep === 2">
|
||||
<p class="text-2xl font-semibold leading-tight">
|
||||
회원 가입
|
||||
{{ stepTwoTitle }}
|
||||
</p>
|
||||
<p class="mt-2 text-sm text-[#9ba3af]">
|
||||
처음 생성하는 계정은 관리자 계정으로 자동 생성됩니다.
|
||||
{{ stepTwoDescription }}
|
||||
</p>
|
||||
|
||||
<form class="mt-8 space-y-5" @submit.prevent="goNextStep">
|
||||
<div class="space-y-1.5">
|
||||
<label class="text-xs text-[#d8dee6]">사용자명</label>
|
||||
<label class="text-xs text-[#d8dee6]">{{ isAdminBootstrapMode ? '관리자 이름' : '사용자명' }}</label>
|
||||
<input
|
||||
v-model="form.username"
|
||||
class="auth-form-input h-10 w-full rounded-[8px] border bg-transparent px-3 text-sm outline-none transition-colors"
|
||||
@@ -179,7 +194,7 @@ const goPreviousStep = () => {
|
||||
</div>
|
||||
|
||||
<div class="space-y-1.5">
|
||||
<label class="text-xs text-[#d8dee6]">이메일</label>
|
||||
<label class="text-xs text-[#d8dee6]">{{ isAdminBootstrapMode ? '관리자 이메일' : '이메일' }}</label>
|
||||
<input
|
||||
v-model="form.email"
|
||||
class="auth-form-input h-10 w-full rounded-[8px] border bg-transparent px-3 text-sm outline-none transition-colors"
|
||||
@@ -193,7 +208,7 @@ const goPreviousStep = () => {
|
||||
</div>
|
||||
|
||||
<div class="space-y-1.5">
|
||||
<label class="text-xs text-[#d8dee6]">비밀번호</label>
|
||||
<label class="text-xs text-[#d8dee6]">{{ isAdminBootstrapMode ? '관리자 비밀번호' : '비밀번호' }}</label>
|
||||
<div
|
||||
class="flex items-center rounded-[8px] border transition-colors focus-within:border-[#2f6feb]"
|
||||
:class="errors.password ? 'border-[#b03b43]' : 'border-[#1a212a]'"
|
||||
@@ -212,7 +227,7 @@ const goPreviousStep = () => {
|
||||
</div>
|
||||
|
||||
<div class="space-y-1.5">
|
||||
<label class="text-xs text-[#d8dee6]">비밀번호 확인</label>
|
||||
<label class="text-xs text-[#d8dee6]">{{ isAdminBootstrapMode ? '관리자 비밀번호 확인' : '비밀번호 확인' }}</label>
|
||||
<div
|
||||
class="flex items-center rounded-[8px] border transition-colors focus-within:border-[#2f6feb]"
|
||||
:class="errors.passwordConfirm ? 'border-[#b03b43]' : 'border-[#1a212a]'"
|
||||
@@ -247,11 +262,11 @@ const goPreviousStep = () => {
|
||||
|
||||
<template v-else>
|
||||
<p class="text-2xl font-semibold leading-tight">
|
||||
회원가입 완료
|
||||
{{ createdAdmin ? '관리자 등록 완료' : '회원가입 완료' }}
|
||||
</p>
|
||||
<p class="mt-2 text-sm text-[#9ba3af]">
|
||||
{{ form.email }} 계정으로 가입되었습니다.<br>
|
||||
이제 로그인 후 댓글을 작성할 수 있습니다.
|
||||
{{ form.email }} 계정으로 {{ createdAdmin ? '관리자 등록' : '가입' }}되었습니다.<br>
|
||||
{{ createdAdmin ? '이제 관리자 화면에서 사이트 운영을 시작할 수 있습니다.' : '이제 로그인 후 댓글을 작성할 수 있습니다.' }}
|
||||
</p>
|
||||
|
||||
<div class="mt-8 rounded-[10px] border border-[#1a212a] bg-[#0d1116] p-4">
|
||||
|
||||
Reference in New Issue
Block a user