Files
web_6ea_educo/ulsan/components/ConsultForm.vue
T

458 lines
11 KiB
Vue

<template>
<section id="consult-section" class="consult-section">
<div class="consult-card">
<div class="consult-header">
<h2 class="consult-title">상담은 무료입니다</h2>
<p class="consult-desc">연락처만 남기시면 확인하는 대로 연락드리겠습니다.</p>
</div>
<div v-if="submitted" class="success-box">
<h3 class="success-title">상담 신청이 정상적으로 완료되었습니다!</h3>
<p class="success-desc">
남겨주신 부모님 연락처(<strong>{{ form.parentPhone }}</strong>)로 전문 상담 팀장이 확인하는 대로 빠른 시일 내에 연락드리겠습니다.
</p>
<button type="button" class="btn-reset" @click="resetForm">추가 문의하기</button>
</div>
<form v-else class="consult-form" @submit.prevent="handleSubmit">
<div class="form-grid">
<!-- 1행 좌: 학생 이름 -->
<div class="form-group">
<label for="c-student-name" class="form-label">학생 이름</label>
<input
id="c-student-name"
v-model="form.studentName"
type="text"
placeholder="홍길동"
required
class="form-input"
/>
</div>
<!-- 1행 우: 부모님 연락처 -->
<div class="form-group">
<label for="c-parent-phone" class="form-label">부모님 연락처</label>
<input
id="c-parent-phone"
v-model="form.parentPhone"
type="tel"
placeholder="010-0000-0000"
required
class="form-input"
/>
</div>
<!-- 2행 좌: 다니는 학교 -->
<div class="form-group">
<label for="c-school" class="form-label">다니는 학교</label>
<input
id="c-school"
v-model="form.schoolName"
type="text"
placeholder="OO고등학교"
class="form-input"
/>
</div>
<!-- 2행 우: 학년 -->
<div class="form-group">
<label for="c-grade" class="form-label">학년</label>
<div class="select-wrap">
<select id="c-grade" v-model="form.grade" class="form-select" required>
<option value="초등">초등</option>
<option value="중1">중1</option>
<option value="중2">중2</option>
<option value="중3">중3</option>
<option value="고1">고1</option>
<option value="고2">고2</option>
<option value="고3">고3</option>
<option value="N수">N수</option>
</select>
</div>
</div>
<!-- 3행 전체: 사는 곳 -->
<div class="form-group full-width">
<label for="c-location" class="form-label">사는 곳</label>
<input
id="c-location"
v-model="form.location"
type="text"
:placeholder="regionName || '행복시 행복동'"
class="form-input"
/>
</div>
<!-- 4행 전체: 상담문의 내용 (선택) -->
<div class="form-group full-width">
<label for="c-memo" class="form-label">상담문의 내용 (선택)</label>
<textarea
id="c-memo"
v-model="form.memo"
rows="4"
placeholder="지금 등급, 어려운 과목, 원하는 시간대 같은 것을 적어 주시면 상담이 빨라집니다."
class="form-textarea"
></textarea>
</div>
</div>
<!-- 개인정보 수집 동의 -->
<div class="privacy-wrap">
<label class="privacy-label">
<input type="checkbox" v-model="form.agree" required class="privacy-checkbox" />
<span>상담을 위해 학생 이름과 부모님 연락처를 받는 데 동의합니다. 받은 정보는 상담 외에 쓰지 않습니다.</span>
</label>
</div>
<!-- 버튼 그룹 -->
<div class="button-group">
<button type="submit" class="btn-submit" :disabled="loading">
<span v-if="loading">문의 전송 중...</span>
<span v-else>문의 보내기</span>
</button>
<a href="tel:010-5961-5807" class="btn-call">
전화로 바로 상담
</a>
</div>
</form>
</div>
</section>
</template>
<script setup>
import { ref, watch } from 'vue'
const props = defineProps({
regionName: {
type: String,
default: ''
},
defaultGrade: {
type: String,
default: '고1'
},
defaultSubject: {
type: String,
default: ''
}
})
function resolveGrade(g) {
if (!g) return '고1'
if (g.includes('고1') || g.includes('고등학교 1')) return '고1'
if (g.includes('고2') || g.includes('고등학교 2')) return '고2'
if (g.includes('고3') || g.includes('고등학교 3')) return '고3'
if (g.includes('중1') || g.includes('중학교 1')) return '중1'
if (g.includes('중2') || g.includes('중학교 2')) return '중2'
if (g.includes('중3') || g.includes('중학교 3')) return '중3'
if (g.includes('초등')) return '초등'
if (g.includes('고등')) return '고1'
if (g.includes('중등') || g.includes('중학')) return '중2'
return '고1'
}
const form = ref({
studentName: '',
parentPhone: '',
schoolName: '',
grade: resolveGrade(props.defaultGrade),
location: props.regionName || '',
memo: '',
agree: false
})
watch(() => props.defaultGrade, (newVal) => {
if (newVal) form.value.grade = resolveGrade(newVal)
})
watch(() => props.regionName, (newVal) => {
if (newVal && !form.value.location) form.value.location = newVal
})
const loading = ref(false)
const submitted = ref(false)
const handleSubmit = async () => {
if (!form.value.parentPhone) return
loading.value = true
try {
const currentUrl = typeof window !== 'undefined' ? window.location.href : ''
await $fetch('/api/consult', {
method: 'POST',
body: {
studentName: form.value.studentName,
parentPhone: form.value.parentPhone,
schoolName: form.value.schoolName,
grade: form.value.grade,
location: form.value.location || props.regionName,
memo: form.value.memo,
url: currentUrl
}
})
submitted.value = true
} catch (err) {
console.error('상담 신청 전송:', err)
submitted.value = true
} finally {
loading.value = false
}
}
const resetForm = () => {
form.value = {
studentName: '',
parentPhone: '',
schoolName: '',
grade: resolveGrade(props.defaultGrade),
location: props.regionName || '',
memo: '',
agree: false
}
submitted.value = false
}
</script>
<style scoped>
.consult-section {
width: 100%;
padding: clamp(35px, 6vw, 65px) 16px;
display: flex;
justify-content: center;
align-items: center;
background: transparent;
}
.consult-card {
width: 100%;
max-width: 580px;
background: #ffffff;
border: 1.5px solid rgba(225, 29, 72, 0.18);
border-radius: 18px;
box-shadow: 0 20px 40px rgba(225, 29, 72, 0.08), 0 4px 12px rgba(15, 23, 42, 0.04);
padding: clamp(24px, 5vw, 42px) clamp(20px, 4vw, 36px);
box-sizing: border-box;
position: relative;
overflow: hidden;
}
.consult-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, #e11d48 0%, #f59e0b 100%);
}
.consult-header {
margin-bottom: 24px;
}
.consult-title {
font-size: clamp(1.45rem, 3.5vw, 1.85rem);
font-weight: 800;
color: #09090b;
letter-spacing: -0.5px;
margin-bottom: 8px;
line-height: 1.3;
}
.consult-desc {
font-size: clamp(0.88rem, 2.2vw, 0.98rem);
color: #475569;
line-height: 1.5;
letter-spacing: -0.3px;
}
.form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
margin-bottom: 18px;
}
.form-group {
display: flex;
flex-direction: column;
gap: 6px;
}
.form-group.full-width {
grid-column: 1 / -1;
}
.form-label {
font-size: 0.88rem;
font-weight: 700;
color: #1e293b;
letter-spacing: -0.3px;
}
.form-input,
.form-select,
.form-textarea {
width: 100%;
padding: 12px 14px;
font-size: 0.95rem;
font-family: inherit;
color: #1e293b;
background: #f8fafc;
border: 1px solid #cbd5e1;
border-radius: 10px;
outline: none;
transition: all 0.2s ease;
box-sizing: border-box;
}
.form-input::placeholder,
.form-textarea::placeholder {
color: #94a3b8;
font-size: 0.9rem;
}
.form-input:focus,
.form-select:focus,
.form-textarea:focus {
border-color: #e11d48;
box-shadow: 0 0 0 3px rgba(225, 29, 72, 0.15);
background: #ffffff;
}
.select-wrap {
position: relative;
width: 100%;
}
.form-select {
appearance: none;
cursor: pointer;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23e11d48' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 14px center;
padding-right: 36px;
}
.form-textarea {
resize: vertical;
min-height: 90px;
line-height: 1.5;
}
.privacy-wrap {
margin-bottom: 22px;
}
.privacy-label {
display: flex;
align-items: flex-start;
gap: 10px;
font-size: 0.82rem;
color: #64748b;
line-height: 1.45;
cursor: pointer;
}
.privacy-checkbox {
margin-top: 3px;
cursor: pointer;
width: 16px;
height: 16px;
accent-color: #e11d48;
}
.button-group {
display: flex;
flex-direction: column;
gap: 12px;
}
.btn-submit {
width: 100%;
padding: 16px 20px;
font-size: 1.08rem;
font-weight: 800;
color: #ffffff;
background: linear-gradient(135deg, #e11d48 0%, #be123c 100%);
border: none;
border-radius: 12px;
cursor: pointer;
transition: all 0.2s ease;
letter-spacing: -0.3px;
box-shadow: 0 6px 18px rgba(225, 29, 72, 0.35);
}
.btn-submit:hover:not(:disabled) {
background: linear-gradient(135deg, #f43f5e 0%, #e11d48 100%);
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(225, 29, 72, 0.45);
}
.btn-submit:disabled {
opacity: 0.7;
cursor: not-allowed;
}
.btn-call {
display: block;
width: 100%;
padding: 15px 20px;
font-size: 1.02rem;
font-weight: 800;
text-align: center;
color: #e11d48;
background: #fff1f2;
border: 2px solid #e11d48;
border-radius: 12px;
cursor: pointer;
text-decoration: none;
transition: all 0.2s ease;
letter-spacing: -0.3px;
box-sizing: border-box;
}
.btn-call:hover {
background: #ffe4e6;
border-color: #be123c;
color: #be123c;
}
.success-box {
text-align: center;
padding: 40px 20px;
}
.success-title {
font-size: 1.25rem;
font-weight: 800;
color: #0f172a;
margin-bottom: 12px;
}
.success-desc {
font-size: 0.95rem;
color: #475569;
line-height: 1.6;
margin-bottom: 24px;
}
.btn-reset {
padding: 10px 24px;
font-size: 0.9rem;
font-weight: 700;
color: #1e3a8a;
background: transparent;
border: 1px solid #1e3a8a;
border-radius: 8px;
cursor: pointer;
}
@media (max-width: 520px) {
.form-grid {
grid-template-columns: 1fr;
gap: 14px;
}
}
</style>