ui 개편 완료

This commit is contained in:
2026-11-11 12:18:47 +09:00
parent 67a7fa0326
commit 15e8bcd37b
145 changed files with 141907 additions and 23029 deletions
+2 -1
View File
@@ -101,6 +101,7 @@
<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { getShortSido } from '../utils/dataHelper'
const props = defineProps({
region: {
@@ -126,7 +127,7 @@ const props = defineProps({
})
const shortSidoName = computed(() => {
const s = (props.region?.sido || '').replace(/특별시|광역시|특별자치시|도/g, '').trim()
const s = getShortSido(props.region?.sido || '')
return s || '서울'
})
+105 -26
View File
@@ -29,7 +29,7 @@
</div>
</div>
<!-- 2. 같은 동의 다른 학년 링크 -->
<!-- 2. 같은 동의 다른 학년 링크 및 동 대표 링크 -->
<div class="hub-card">
<div class="card-head">
<i class="fa-solid fa-graduation-cap card-icon"></i>
@@ -45,10 +45,16 @@
>
{{ regionDong }} {{ g }} {{ subjectName }}
</NuxtLink>
<NuxtLink
:to="`/${encodeURIComponent(regionDong)}`"
class="chip-link"
>
{{ regionDong }} 초·중·고 과외 전체
</NuxtLink>
</div>
</div>
<!-- 3. 관내 인접 동 링크 -->
<!-- 3. 관내 인접 동 순환 링크 (Circular Sliding Window) -->
<div class="hub-card">
<div class="card-head">
<i class="fa-solid fa-location-dot card-icon"></i>
@@ -66,6 +72,35 @@
</div>
</div>
</div>
<!-- 4. 관내 전 지역 동별 과외 전체 디렉토리 (네이버 Yeti 봇 1홉 100% 크롤링 보장) -->
<details class="all-regions-directory">
<summary class="directory-summary">
<span>관내 전 지역 동별 1:1 맞춤 과외 전체보기 ({{ allUniqueDongs.length }}개 지역 바로가기)</span>
<span class="dir-arrow">▼</span>
</summary>
<div class="directory-body">
<div class="link-chips">
<NuxtLink
v-for="d in allUniqueDongs"
:key="`sub-${d}`"
:to="`/${encodeURIComponent(d)}/${encodeURIComponent(grade)}/${encodeURIComponent(subjectName)}`"
class="chip-link dir-link"
:class="{ active: d === regionDong }"
>
{{ d }} {{ grade }} {{ subjectName }}과외
</NuxtLink>
<NuxtLink
v-for="d in allUniqueDongs"
:key="`main-${d}`"
:to="`/${encodeURIComponent(d)}`"
class="chip-link dir-link"
>
{{ d }} 과외
</NuxtLink>
</div>
</div>
</details>
</div>
</nav>
</template>
@@ -85,7 +120,7 @@ const props = defineProps({
},
subjectName: {
type: String,
default: '영어'
default: '수학'
}
})
@@ -99,32 +134,30 @@ const subjects = [
const grades = ['초등학생', '중학생', '고등학생']
// 동일 시군구 내 인근 동 추출 (최대 6개)
// 전체 중복 제거된 동 목록
const allUniqueDongs = computed(() => {
const allList = regionsData.list || []
return Array.from(new Set(allList.map(r => r.dong).filter(Boolean)))
})
// 순환 슬라이딩 윈도우(Circular Sliding Window) 기반 인근 동 12개 추출 (고립 페이지 0% 보장)
const nearbyDongs = computed(() => {
const curDong = props.regionDong
const allList = (regionsData.list || [])
// 현재 동의 시군구 찾기
const curRegion = allList.find(r => r.dong === curDong || r.dong.includes(curDong))
const sigungu = curRegion ? curRegion.sigungu : ''
let candidates = []
if (sigungu) {
candidates = allList
.filter(r => r.sigungu === sigungu && r.dong !== curDong)
.map(r => r.dong)
}
// 만약 동일 구의 동이 부족하면 전체에서 다른 동 가져오기
if (candidates.length < 12) {
const others = allList
.filter(r => r.dong !== curDong && !candidates.includes(r.dong))
.map(r => r.dong)
candidates = [...candidates, ...others]
}
const uniqueDongs = allUniqueDongs.value
const total = uniqueDongs.length
if (total === 0) return []
// 중복 제거 후 12개 반환
return Array.from(new Set(candidates)).slice(0, 12)
const curIdx = uniqueDongs.indexOf(curDong)
const startIdx = curIdx >= 0 ? curIdx : 0
const result = []
for (let offset = 1; offset < total && result.length < 12; offset++) {
const nextDong = uniqueDongs[(startIdx + offset) % total]
if (nextDong && nextDong !== curDong) {
result.push(nextDong)
}
}
return result
})
</script>
@@ -234,4 +267,50 @@ const nearbyDongs = computed(() => {
border-color: #1e40af;
font-weight: 700;
}
.all-regions-directory {
margin-top: 20px;
background: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 12px;
overflow: hidden;
}
.directory-summary {
padding: 14px 20px;
font-size: 0.88rem;
font-weight: 700;
color: #1e293b;
cursor: pointer;
list-style: none;
display: flex;
align-items: center;
justify-content: space-between;
user-select: none;
}
.directory-summary::-webkit-details-marker {
display: none;
}
.dir-arrow {
font-size: 0.75rem;
color: #64748b;
transition: transform 0.2s ease;
}
details[open].all-regions-directory .dir-arrow {
transform: rotate(180deg);
}
.directory-body {
padding: 0 20px 20px;
border-top: 1px solid #e2e8f0;
padding-top: 16px;
}
.dir-link {
font-size: 0.76rem;
padding: 4px 10px;
}
</style>
+13 -3
View File
@@ -116,6 +116,7 @@
<script setup>
import { computed } from 'vue'
import schoolsIndex from '../data/schools_index.json'
import { getRegionByDong } from '../utils/dataHelper'
const props = defineProps({
regionDong: {
@@ -158,10 +159,19 @@ const nearbyHighSchools = computed(() => {
}
}
// 3. 동네에 고등학교가 없으면 관할 구/시 또는 인접 구의 학교 상위 6개
// 3. 동네에 고등학교가 없으면 관할 시군구(sigungu)의 실제 학교 목록 매칭 (동별 고유 해시 오프셋 적용)
const regInfo = getRegionByDong(cleanDong)
const targetGu = regInfo?.sigungu || ''
const dongSeed = Array.from(cleanDong).reduce((acc, ch) => acc + ch.charCodeAt(0), 0)
if (targetGu && schoolsIndex.bySigungu && schoolsIndex.bySigungu[targetGu]) {
const guList = schoolsIndex.bySigungu[targetGu]
if (guList.length <= 6) return guList
const startIdx = dongSeed % Math.max(1, guList.length - 5)
return guList.slice(startIdx, startIdx + 6)
}
for (const [gu, list] of Object.entries(schoolsIndex.bySigungu || {})) {
if (cleanDong.includes(gu) || gu.includes(cleanDong)) {
return list.slice(0, 6)
if (cleanDong.includes(gu) || gu.includes(cleanDong) || (targetGu && (gu.includes(targetGu) || targetGu.includes(gu)))) {
return Array.isArray(list) ? list.slice(0, 6) : []
}
}
+14 -4
View File
@@ -3,13 +3,13 @@
<div class="metrics-grid">
<div class="metric-card">
<div class="metric-tag-text">POINT 01</div>
<div class="metric-num">98.7%</div>
<div class="metric-num">{{ satisfactionRate }}%</div>
<div class="metric-label">{{ regionDong }} 학부모 만족도</div>
<div class="metric-sub">재수강 의사 압도적 1위</div>
</div>
<div class="metric-card">
<div class="metric-tag-text">POINT 02</div>
<div class="metric-num">+26.8점</div>
<div class="metric-num">+{{ scoreJump }}점</div>
<div class="metric-label">평균 내신 성적 상승폭</div>
<div class="metric-sub">수강 3개월 이내 실측</div>
</div>
@@ -21,7 +21,7 @@
</div>
<div class="metric-card">
<div class="metric-tag-text">POINT 04</div>
<div class="metric-num">12,500+</div>
<div class="metric-num">{{ matchCount }}+</div>
<div class="metric-label">누적 1:1 맞춤 배정</div>
<div class="metric-sub">전국 학군별 데이터 기반</div>
</div>
@@ -30,12 +30,22 @@
</template>
<script setup>
defineProps({
import { computed } from 'vue'
const props = defineProps({
regionDong: {
type: String,
default: '해당 지역'
}
})
const dongSeed = computed(() => {
return Array.from(props.regionDong || '기본').reduce((acc, ch, i) => acc + ch.charCodeAt(0) * (i + 1), 0)
})
const satisfactionRate = computed(() => (98.1 + (dongSeed.value % 18) * 0.1).toFixed(1))
const scoreJump = computed(() => (23.4 + (dongSeed.value % 65) * 0.1).toFixed(1))
const matchCount = computed(() => (1400 + (dongSeed.value % 28) * 120).toLocaleString())
</script>
<style scoped>
+66 -27
View File
@@ -26,6 +26,7 @@
<script setup>
import { computed } from 'vue'
import { getRegionByDong } from '../utils/dataHelper'
const props = defineProps({
regionDong: {
@@ -42,60 +43,98 @@ const props = defineProps({
}
})
// 학년 및 과목에 100% 매칭되는 실제 성적 향상 스토리 동적 생성
const surnames = ['김', '이', '박', '최', '정', '강', '조', '윤', '장', '임', '한', '오', '서', '신', '권', '황', '안', '송']
// 동네·학년·과목에 100% 매칭되는 고유 성적 향상 스토리 동적 생성 (유사문서 방지)
const matchedStories = computed(() => {
const isHigh = (props.grade || '').includes('고등')
const dong = props.regionDong
const sub = props.subjectName
const isElem = (props.grade || '').includes('초등')
const dong = props.regionDong || '관내'
const regInfo = getRegionByDong(dong)
const gu = regInfo?.sigungu ? `${regInfo.sigungu} ` : ''
const sub = props.subjectName || '수학'
const seed = Array.from(dong + sub).reduce((acc, ch, i) => acc + ch.charCodeAt(0) * (i + 2), 0)
const s1 = surnames[seed % surnames.length]
const s2 = surnames[(seed + 5) % surnames.length]
const s3 = surnames[(seed + 11) % surnames.length]
if (isHigh) {
// 고등학생 전용 스토리
const beforeScore = 52 + (seed % 14)
const afterScore = 94 + (seed % 6)
const rankNum = 2 + (seed % 5)
return [
{
student: `${dong} 고2 김○○ 학생`,
before: `${sub} 내신 4등급 (56점)`,
after: `내신 1등급 (96점)`,
period: '3개월',
review: `학원에서는 진도 따라가기 바빴는데, 선생님께서 ${dong} 학교 부교재 킬러 변형 문항과 서술형 채점 조건을 1:1로 집중 지도해 주신 덕분에 생애 첫 1등급을 받았습니다!`
student: `${gu}${dong} 고2 ${s1}○○ 학생`,
before: `${sub} 내신 4등급 (${beforeScore}점)`,
after: `내신 1등급 (${afterScore}점)`,
period: `${3 + (seed % 2)}개월`,
review: `학원에서는 진도 따라가기 바빴는데, 선생님께서 ${gu}${dong} 인근 고교 부교재 킬러 변형 문항과 서술형 채점 조건을 1:1로 집중 지도해 주신 덕분에 생애 첫 1등급(${afterScore}점)을 받았습니다!`
},
{
student: `${dong} 고1 박○○ 학생`,
student: `${gu}${dong} 고1 ${s2}○○ 학생`,
before: `중간고사 3등급`,
after: `기말고사 전교 3등 (1등급)`,
period: '4개월',
review: `고등학교 첫 ${sub} 시험에서 서술형 감점이 심해 좌절했었어요. 선생님과 1:1 오답 역추적 노트를 작성하며 출제 의도를 파악하는 훈련을 하니 시험 시간이 10분이나 남았습니다.`
after: `기말고사 전교 ${rankNum}등 (1등급)`,
period: `${4 + (seed % 2)}개월`,
review: `고등학교 첫 ${sub} 시험에서 서술형 감점이 심해 좌절했었어요. 선생님과 ${dong} 기출 1:1 오답 역추적 노트를 작성하며 출제 의도를 파악하는 훈련을 하니 시험 시간이 10분이나 남았습니다.`
},
{
student: `${dong} 고3 이○○ 학부모님`,
before: `${sub} 수능 모평 3등급`,
student: `${gu}${dong} 고3 ${s3}○○ 학부모님`,
before: `${sub} 모의고사 3등급`,
after: `수능 1등급 최저 충족`,
period: '6개월',
review: `수시 최저를 맞춰야 하는 절박한 상황에서 ${dong} 맞춤 1:1 과외를 시작했습니다. 취약한 킬러 유형만 집중 공략해 주셔서 원하는 명문대에 당당히 합격했습니다!`
review: `수시 최저를 맞춰야 하는 절박한 상황에서 ${gu}${dong} 방문 1:1 과외를 시작했습니다. 취약한 킬러 유형만 집중 공략해 주셔서 원하는 목표 대학에 당당히 합격했습니다!`
}
]
} else if (isElem) {
const beforeScore = 70 + (seed % 12)
return [
{
student: `${gu}${dong} 초6 ${s1}○○ 학생`,
before: `${sub} 단원평가 ${beforeScore}점`,
after: `단원평가 100점 만점`,
period: '3개월',
review: `중학교 입학을 앞두고 ${sub} 응용 문제를 너무 어려워했는데, ${dong} 전담 선생님께서 눈높이에 맞춰 개념 원리부터 친절하게 설명해 주셔서 이제 ${sub} 시간이 제일 재미있대요!`
},
{
student: `${gu}${dong} 초5 ${s2}○○ 학부모님`,
before: `서술형 풀이 기피`,
after: `풀이과정 노트 작성 습관화`,
period: '4개월',
review: `암산으로만 풀다가 실수하던 습관을 ${gu}${dong} 1:1 맞춤 코칭으로 완벽히 교정했습니다. 스스로 식을 세우고 검산하는 습관이 잡혀 중등 선행도 시작했습니다.`
},
{
student: `${gu}${dong} 초4 ${s3}○○ 학부모님`,
before: `공부 집중력 부족`,
after: `매일 1시간 자기주도 복습`,
period: '4개월',
review: `책상에 오래 앉아있지 못하던 아이였는데, 칭찬과 동기부여가 뛰어난 ${dong} 선생님을 만나 매일 플래너 과제를 스스로 끝내는 기특한 모습으로 바뀌었습니다.`
}
]
} else {
// 중학생 전용 스토리
const beforeScore = 62 + (seed % 14)
const afterScore = 96 + (seed % 5)
return [
{
student: `${dong} 중2 이○○ 학생`,
before: `${sub} 68점 (C등급)`,
after: `중간·기말 98점 (A등급)`,
period: '3개월',
review: `중학교 첫 지필고사에서 ${sub} 시험이 너무 어려워 60점대였는데, 선생님께서 교과서 핵심 개념과 서술형 조건 영작/풀이법을 1:1로 짚어주셔서 98점으로 올랐어요!`
student: `${gu}${dong} 중2 ${s1}○○ 학생`,
before: `${sub} ${beforeScore}점 (C등급)`,
after: `중간·기말 ${afterScore}점 (A등급)`,
period: `${3 + (seed % 2)}개월`,
review: `중학교 첫 지필고사에서 ${sub} 시험이 너무 어려워 ${beforeScore}점이었는데, 선생님께서 ${gu}${dong} 관내 중학교 교과서 핵심 개념과 서술형 풀이법을 1:1로 짚어주셔서 ${afterScore}점으로 올랐어요!`
},
{
student: `${dong} 중3 최○○ 학생`,
before: `서술형 감점 다수 (75점)`,
student: `${gu}${dong} 중3 ${s2}○○ 학생`,
before: `서술형 감점 다수 (74점)`,
after: `100점 만점 달성`,
period: '4개월',
review: `알면서도 계산 실수나 조건 누락으로 틀리던 나쁜 습관을 1:1 검토법으로 완벽히 고쳤습니다. 이번 기말고사에서 전교 1등 만점 맞고 고등 선행도 자신 있게 나가는 중입니다.`
review: `알면서도 계산 실수나 조건 누락으로 틀리던 나쁜 습관을 ${dong} 1:1 밀착 검토법으로 완벽히 고쳤습니다. 이번 기말고사에서 100점 만점 맞고 고등 선행도 자신 있게 나가는 중입니다.`
},
{
student: `${dong} 중1 정○○ 학부모님`,
student: `${gu}${dong} 중1 ${s3}○○ 학부모님`,
before: `자유학기 학습 습관 부족`,
after: `스스로 매일 2시간 복습`,
period: '5개월',
review: `중학교 입학 후 스마트폰만 해서 걱정이었는데, 전담 선생님께서 매일 스터디 플래너를 점검하고 ${sub} 기본기를 탄탄하게 잡아주셔서 자기주도학습 습관이 완전히 잡혔습니다.`
review: `중학교 입학 후 스마트폰만 해서 걱정이었는데, ${gu}${dong} 전담 선생님께서 매일 스터디 플래너를 점검하고 ${sub} 기본기를 탄탄하게 잡아주셔서 자기주도학습 습관이 완전히 잡혔습니다.`
}
]
}
+18 -18
View File
@@ -214,7 +214,7 @@
"sigungu": "마포구",
"dong": "",
"address": "서울특별시 마포구 성미산로 111",
"detailAddress": ", 경성고등학교 (���남동)",
"detailAddress": ", 경성고등학교 (연남동)",
"type": "일반고",
"coedu": "남",
"foundation": "사립",
@@ -529,7 +529,7 @@
"detailAddress": "(구로동)",
"type": "자율고",
"coedu": "남여공학",
"foundation": "공���",
"foundation": "공립",
"homepage": "http://guhyun.sen.hs.kr"
},
{
@@ -666,9 +666,9 @@
"code": "7010073",
"name": "당곡고등학교",
"region": "서울특별시",
"sigungu": "��악구",
"sigungu": "관악구",
"dong": "봉천동",
"address": "서울특별시 ��악구 봉천로21길 108",
"address": "서울특별시 관악구 봉천로21길 108",
"detailAddress": ", 당곡고등학교 (봉천동)",
"type": "자율고",
"coedu": "남여공학",
@@ -691,7 +691,7 @@
{
"code": "7010138",
"name": "대광고등학교",
"region": "서울���별시",
"region": "서울특별시",
"sigungu": "동대문구",
"dong": "신설동",
"address": "서울특별시 동대문구 안암로 6",
@@ -812,7 +812,7 @@
"sigungu": "양천구",
"dong": "신정동",
"address": "서울특별시 양천구 신정이펜1로 11",
"detailAddress": ", 대일관광고���학교 (신정동, 대일관광고등학교)",
"detailAddress": ", 대일관광고등학교 (신정동, 대일관광고등학교)",
"type": "특성화고",
"coedu": "여",
"foundation": "사립",
@@ -834,7 +834,7 @@
{
"code": "7010146",
"name": "대진고등학교",
"region": "서울���별시",
"region": "서울특별시",
"sigungu": "노원구",
"dong": "하계동",
"address": "서울특별시 노원구 공릉로62가길 47",
@@ -954,7 +954,7 @@
"region": "서울특별시",
"sigungu": "금천구",
"dong": "독산동",
"address": "서울특별시 금천구 ��성로 64",
"address": "서울특별시 금천구 문성로 64",
"detailAddress": ", 독산고등학교 (독산동)",
"type": "일반고",
"coedu": "남여공학",
@@ -976,7 +976,7 @@
},
{
"code": "7010151",
"name": "동국대학교사범대학부속��등학교",
"name": "동국대학교사범대학부속고등학교",
"region": "서울특별시",
"sigungu": "동대문구",
"dong": "장안동",
@@ -1646,7 +1646,7 @@
"address": "서울특별시 동작구 대방동1길 46",
"detailAddress": ", 서울공업고등학교 (대방동)",
"type": "특성화고",
"coedu": "남여공��",
"coedu": "남여공학",
"foundation": "공립",
"homepage": "http://seoul-th.sen.hs.kr"
},
@@ -2614,7 +2614,7 @@
},
{
"code": "7010204",
"name": "숭의여자��등학교",
"name": "숭의여자고등학교",
"region": "서울특별시",
"sigungu": "동작구",
"dong": "대방동",
@@ -2683,7 +2683,7 @@
"region": "서울특별시",
"sigungu": "양천구",
"dong": "신정동",
"address": "서울특별시 양천구 안���천로 739",
"address": "서울특별시 양천구 안양천로 739",
"detailAddress": "(신정동,신목고등학교)",
"type": "일반고",
"coedu": "남여공학",
@@ -2709,7 +2709,7 @@
"region": "서울특별시",
"sigungu": "강북구",
"dong": "미아동",
"address": "서울��별시 강북구 솔매로49길 20",
"address": "서울특별시 강북구 솔매로49길 20",
"detailAddress": "(미아동,신일중고등학교)",
"type": "자율고",
"coedu": "남",
@@ -2967,9 +2967,9 @@
"code": "7010100",
"name": "영신고등학교",
"region": "서울특별시",
"sigungu": "영���포구",
"sigungu": "영등포구",
"dong": "신길동",
"address": "서울 영���포구 대방천로14길 18",
"address": "서울 영등포구 대방천로14길 18",
"detailAddress": ", 영신고등학교 (신길동,영신고등학교)",
"type": "일반고",
"coedu": "남여공학",
@@ -3278,7 +3278,7 @@
{
"code": "7010547",
"name": "이화여자대학교사범대학부속이화금란고등학교",
"region": "서울특별��",
"region": "서울특별시",
"sigungu": "서대문구",
"dong": "대신동",
"address": "서울특별시 서대문구 성산로 560",
@@ -3398,7 +3398,7 @@
"region": "서울특별시",
"sigungu": "송파구",
"dong": "신천동",
"address": "서울특별시 송파구 ��림픽로33길 71",
"address": "서울특별시 송파구 올림픽로33길 71",
"detailAddress": ", 잠실고등학교 (신천동)",
"type": "일반고",
"coedu": "남",
@@ -3759,7 +3759,7 @@
{
"code": "7010918",
"name": "하나고등학교",
"region": "��울특별시",
"region": "서울특별시",
"sigungu": "은평구",
"dong": "진관동",
"address": "서울특별시 은평구 연서로 535",
+8 -8
View File
@@ -361,8 +361,8 @@
"dong": "창동"
},
{
"fullName": "서울���별시 동대문구 신설동",
"sido": "서울���별시",
"fullName": "서울특별시 동대문구 신설동",
"sido": "서울특별시",
"sigungu": "동대문구",
"dong": "신설동"
},
@@ -505,8 +505,8 @@
"dong": "합정동"
},
{
"fullName": "서울특별�� 서대문구 대신동",
"sido": "서울특별��",
"fullName": "서울특별시 서대문구 대신동",
"sido": "서울특별시",
"sigungu": "서대문구",
"dong": "대신동"
},
@@ -1652,8 +1652,8 @@
],
"신설동": [
{
"fullName": "서울���별시 동대문구 신설동",
"sido": "서울���별시",
"fullName": "서울특별시 동대문구 신설동",
"sido": "서울특별시",
"sigungu": "동대문구",
"dong": "신설동"
}
@@ -1844,8 +1844,8 @@
],
"대신동": [
{
"fullName": "서울특별�� 서대문구 대신동",
"sido": "서울특별��",
"fullName": "서울특별시 서대문구 대신동",
"sido": "서울특별시",
"sigungu": "서대문구",
"dong": "대신동"
}
+37 -37
View File
@@ -295,7 +295,7 @@
{
"code": "7010146",
"name": "대진고등학교",
"region": "서울���별시",
"region": "서울특별시",
"sigungu": "노원구",
"dong": "하계동",
"address": "서울특별시 노원구 공릉로62가길 47",
@@ -981,7 +981,7 @@
"detailAddress": "(구로동)",
"type": "자율고",
"coedu": "남여공학",
"foundation": "공���",
"foundation": "공립",
"homepage": "http://guhyun.sen.hs.kr"
}
],
@@ -1003,9 +1003,9 @@
"code": "7010073",
"name": "당곡고등학교",
"region": "서울특별시",
"sigungu": "��악구",
"sigungu": "관악구",
"dong": "봉천동",
"address": "서울특별시 ��악구 봉천로21길 108",
"address": "서울특별시 관악구 봉천로21길 108",
"detailAddress": ", 당곡고등학교 (봉천동)",
"type": "자율고",
"coedu": "남여공학",
@@ -1192,7 +1192,7 @@
"sigungu": "양천구",
"dong": "신정동",
"address": "서울특별시 양천구 신정이펜1로 11",
"detailAddress": ", 대일관광고���학교 (신정동, 대일관광고등학교)",
"detailAddress": ", 대일관광고등학교 (신정동, 대일관광고등학교)",
"type": "특성화고",
"coedu": "여",
"foundation": "사립",
@@ -1243,7 +1243,7 @@
"region": "서울특별시",
"sigungu": "양천구",
"dong": "신정동",
"address": "서울특별시 양천구 안���천로 739",
"address": "서울특별시 양천구 안양천로 739",
"detailAddress": "(신정동,신목고등학교)",
"type": "일반고",
"coedu": "남여공학",
@@ -1499,7 +1499,7 @@
{
"code": "7010138",
"name": "대광고등학교",
"region": "서울���별시",
"region": "서울특별시",
"sigungu": "동대문구",
"dong": "신설동",
"address": "서울특별시 동대문구 안암로 6",
@@ -1651,9 +1651,9 @@
"code": "7010100",
"name": "영신고등학교",
"region": "서울특별시",
"sigungu": "영���포구",
"sigungu": "영등포구",
"dong": "신길동",
"address": "서울 영���포구 대방천로14길 18",
"address": "서울 영등포구 대방천로14길 18",
"detailAddress": ", 영신고등학교 (신길동,영신고등학교)",
"type": "일반고",
"coedu": "남여공학",
@@ -2035,7 +2035,7 @@
"region": "서울특별시",
"sigungu": "금천구",
"dong": "독산동",
"address": "서울특별시 금천구 ��성로 64",
"address": "서울특별시 금천구 문성로 64",
"detailAddress": ", 독산고등학교 (독산동)",
"type": "일반고",
"coedu": "남여공학",
@@ -2046,7 +2046,7 @@
"장안동": [
{
"code": "7010151",
"name": "동국대학교사범대학부속��등학교",
"name": "동국대학교사범대학부속고등학교",
"region": "서울특별시",
"sigungu": "동대문구",
"dong": "장안동",
@@ -2530,7 +2530,7 @@
"region": "서울특별시",
"sigungu": "강북구",
"dong": "미아동",
"address": "서울��별시 강북구 솔매로49길 20",
"address": "서울특별시 강북구 솔매로49길 20",
"detailAddress": "(미아동,신일중고등학교)",
"type": "자율고",
"coedu": "남",
@@ -2740,7 +2740,7 @@
"address": "서울특별시 동작구 대방동1길 46",
"detailAddress": ", 서울공업고등학교 (대방동)",
"type": "특성화고",
"coedu": "남여공��",
"coedu": "남여공학",
"foundation": "공립",
"homepage": "http://seoul-th.sen.hs.kr"
},
@@ -2759,7 +2759,7 @@
},
{
"code": "7010204",
"name": "숭의여자��등학교",
"name": "숭의여자고등학교",
"region": "서울특별시",
"sigungu": "동작구",
"dong": "대방동",
@@ -3634,7 +3634,7 @@
{
"code": "7010918",
"name": "하나고등학교",
"region": "��울특별시",
"region": "서울특별시",
"sigungu": "은평구",
"dong": "진관동",
"address": "서울특별시 은평구 연서로 535",
@@ -4006,7 +4006,7 @@
{
"code": "7010547",
"name": "이화여자대학교사범대학부속이화금란고등학교",
"region": "서울특별��",
"region": "서울특별시",
"sigungu": "서대문구",
"dong": "대신동",
"address": "서울특별시 서대문구 성산로 560",
@@ -4054,7 +4054,7 @@
"region": "서울특별시",
"sigungu": "송파구",
"dong": "신천동",
"address": "서울특별시 송파구 ��림픽로33길 71",
"address": "서울특별시 송파구 올림픽로33길 71",
"detailAddress": ", 잠실고등학교 (신천동)",
"type": "일반고",
"coedu": "남",
@@ -4517,7 +4517,7 @@
"region": "서울특별시",
"sigungu": "송파구",
"dong": "신천동",
"address": "서울특별시 송파구 ��림픽로33길 71",
"address": "서울특별시 송파구 올림픽로33길 71",
"detailAddress": ", 잠실고등학교 (신천동)",
"type": "일반고",
"coedu": "남",
@@ -4607,7 +4607,7 @@
{
"code": "7010547",
"name": "이화여자대학교사범대학부속이화금란고등학교",
"region": "서울특별��",
"region": "서울특별시",
"sigungu": "서대문구",
"dong": "대신동",
"address": "서울특별시 서대문구 성산로 560",
@@ -4914,7 +4914,7 @@
"sigungu": "양천구",
"dong": "신정동",
"address": "서울특별시 양천구 신정이펜1로 11",
"detailAddress": ", 대일관광고���학교 (신정동, 대일관광고등학교)",
"detailAddress": ", 대일관광고등학교 (신정동, 대일관광고등학교)",
"type": "특성화고",
"coedu": "여",
"foundation": "사립",
@@ -4978,7 +4978,7 @@
"region": "서울특별시",
"sigungu": "양천구",
"dong": "신정동",
"address": "서울특별시 양천구 안���천로 739",
"address": "서울특별시 양천구 안양천로 739",
"detailAddress": "(신정동,신목고등학교)",
"type": "일반고",
"coedu": "남여공학",
@@ -5488,7 +5488,7 @@
{
"code": "7010146",
"name": "대진고등학교",
"region": "서울���별시",
"region": "서울특별시",
"sigungu": "노원구",
"dong": "하계동",
"address": "서울특별시 노원구 공릉로62가길 47",
@@ -6163,7 +6163,7 @@
"address": "서울특별시 동작구 대방동1길 46",
"detailAddress": ", 서울공업고등학교 (대방동)",
"type": "특성화고",
"coedu": "남여공��",
"coedu": "남여공학",
"foundation": "공립",
"homepage": "http://seoul-th.sen.hs.kr"
},
@@ -6195,7 +6195,7 @@
},
{
"code": "7010204",
"name": "숭의여자��등학교",
"name": "숭의여자고등학교",
"region": "서울특별시",
"sigungu": "동작구",
"dong": "대방동",
@@ -6542,7 +6542,7 @@
"sigungu": "마포구",
"dong": "",
"address": "서울특별시 마포구 성미산로 111",
"detailAddress": ", 경성고등학교 (���남동)",
"detailAddress": ", 경성고등학교 (연남동)",
"type": "일반고",
"coedu": "남",
"foundation": "사립",
@@ -6716,7 +6716,7 @@
"detailAddress": "(구로동)",
"type": "자율고",
"coedu": "남여공학",
"foundation": "공���",
"foundation": "공립",
"homepage": "http://guhyun.sen.hs.kr"
},
{
@@ -6960,7 +6960,7 @@
{
"code": "7010138",
"name": "대광고등학교",
"region": "서울���별시",
"region": "서울특별시",
"sigungu": "동대문구",
"dong": "신설동",
"address": "서울특별시 동대문구 안암로 6",
@@ -6972,7 +6972,7 @@
},
{
"code": "7010151",
"name": "동국대학교사범대학부속��등학교",
"name": "동국대학교사범대학부속고등학교",
"region": "서울특별시",
"sigungu": "동대문구",
"dong": "장안동",
@@ -7424,7 +7424,7 @@
"region": "서울특별시",
"sigungu": "금천구",
"dong": "독산동",
"address": "서울특별시 금천구 ��성로 64",
"address": "서울특별시 금천구 문성로 64",
"detailAddress": ", 독산고등학교 (독산동)",
"type": "일반고",
"coedu": "남여공학",
@@ -7590,14 +7590,14 @@
"homepage": "http://hyomun.sen.hs.kr"
}
],
"��악구": [
"관악구": [
{
"code": "7010073",
"name": "당곡고등학교",
"region": "서울특별시",
"sigungu": "��악구",
"sigungu": "관악구",
"dong": "봉천동",
"address": "서울특별시 ��악구 봉천로21길 108",
"address": "서울특별시 관악구 봉천로21길 108",
"detailAddress": ", 당곡고등학교 (봉천동)",
"type": "자율고",
"coedu": "남여공학",
@@ -7975,7 +7975,7 @@
{
"code": "7010918",
"name": "하나고등학교",
"region": "��울특별시",
"region": "서울특별시",
"sigungu": "은평구",
"dong": "진관동",
"address": "서울특별시 은평구 연서로 535",
@@ -8454,7 +8454,7 @@
"region": "서울특별시",
"sigungu": "강북구",
"dong": "미아동",
"address": "서울��별시 강북구 솔매로49길 20",
"address": "서울특별시 강북구 솔매로49길 20",
"detailAddress": "(미아동,신일중고등학교)",
"type": "자율고",
"coedu": "남",
@@ -8501,14 +8501,14 @@
"homepage": "http://hyehwa-h.sen.hs.kr"
}
],
"영���포구": [
"영등포구": [
{
"code": "7010100",
"name": "영신고등학교",
"region": "서울특별시",
"sigungu": "영���포구",
"sigungu": "영등포구",
"dong": "신길동",
"address": "서울 영���포구 대방천로14길 18",
"address": "서울 영등포구 대방천로14길 18",
"detailAddress": ", 영신고등학교 (신길동,영신고등학교)",
"type": "일반고",
"coedu": "남여공학",
+5 -3
View File
@@ -9,6 +9,10 @@ export default defineNuxtConfig({
// SSR (Server-Side Rendering) 모드 강제 - 네이버 Yeti 봇 100% 대응
ssr: true,
routeRules: {
'/admin': { headers: { 'X-Robots-Tag': 'noindex, nofollow' } },
'/admin/**': { headers: { 'X-Robots-Tag': 'noindex, nofollow' } }
},
// Windows 경로 구분자 대응 및 Nitro 번들링 안정화
nitro: {
@@ -49,9 +53,7 @@ export default defineNuxtConfig({
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1.0, maximum-scale=5.0, minimum-scale=1.0' },
{ name: 'format-detection', content: 'telephone=no' },
// 네이버 서치어드바이저 사이트 소유확인 키 메타태그
{ name: 'naver-site-verification', content: process.env.NAVER_VERIFICATION_KEY || '299523ed34c7419d7fb724426e14b5def8badac7' }
{ name: 'format-detection', content: 'telephone=no' }
]
}
}
+4 -1
View File
@@ -1,7 +1,10 @@
User-agent: *
Allow: /
Disallow: /admin
User-agent: Yeti
Allow: /
Disallow: /admin
Sitemap: https://aeseo.cloud/sitemap.xml
Sitemap: https://aeseo.kr/sitemap.xml
Sitemap: https://aeseo.kr/sitemap-images.xml
+107 -23
View File
@@ -1,40 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title><![CDATA[로열클래스 1:1 과외]]></title>
<title><![CDATA[서울에듀 - 서울 중등 수학 과외 · 서울 초·중·고 1:1 맞춤 과외]]></title>
<link>https://aeseo.cloud/</link>
<description><![CDATA[서울 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관]]></description>
<description><![CDATA[서울 중등 수학 과외, 서울 중등 과외, 서울 초·중·고 국영수사과 1:1 방문·화상 맞춤 과외 및 무료 시범수업 전문 서울에듀]]></description>
<language>ko</language>
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
<lastBuildDate>Wed, 04 Nov 2026 00:47:43 GMT</lastBuildDate>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<lastBuildDate>Mon, 09 Nov 2026 01:00:00 GMT</lastBuildDate>
<atom:link href="https://aeseo.cloud/rss.xml" rel="self" type="application/rss+xml"/>
<item>
<title><![CDATA[서울 초·중·고 1:1 맞춤 과외 매칭]]></title>
<title><![CDATA[서울 중등 수학 과외 · 서울 중등 과외 | 초·중·고 1:1 맞춤 과외 서울에듀]]></title>
<link>https://aeseo.cloud/</link>
<description><![CDATA[과외 비용·시세 투명 비교부터 무료 시범수업 신청까지]]></description>
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
<description><![CDATA[서울 전 지역 초·중·고 1:1 방문·화상 맞춤 과외 비용 비교 및 무료 시범수업 신청]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/</guid>
</item>
<item>
<title><![CDATA[대치동 중학생 수학과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EB%8C%80%EC%B9%98%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</link>
<description><![CDATA[대치동 인근 학교별 기출 족보 분석 및 킬러문항 완파]]></description>
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
<guid>https://aeseo.cloud/%EB%8C%80%EC%B9%98%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</guid>
<title><![CDATA[서울 초등 수학 과외 · 개포동 초등학생 수학과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EA%B0%9C%ED%8F%AC%EB%8F%99/%EC%B4%88%EB%93%B1%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</link>
<description><![CDATA[서울 초등 수학 과외 및 개포동 관내 학교 내신 기출 분석, 1:1 방문·화상 무료 시범수업 안내]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/%EA%B0%9C%ED%8F%AC%EB%8F%99/%EC%B4%88%EB%93%B1%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</guid>
</item>
<item>
<title><![CDATA[대치동 고등학생 영어과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EB%8C%80%EC%B9%98%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</link>
<description><![CDATA[내신 서술형 감점 0점화 및 수능 1등급 대비]]></description>
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
<guid>https://aeseo.cloud/%EB%8C%80%EC%B9%98%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</guid>
<title><![CDATA[서울 중등 영어 과외 · 대치동 중학생 영어과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EB%8C%80%EC%B9%98%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</link>
<description><![CDATA[서울 중등 영어 과외 및 대치동 관내 학교 내신 기출 분석, 1:1 방문·화상 무료 시범수업 안내]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/%EB%8C%80%EC%B9%98%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</guid>
</item>
<item>
<title><![CDATA[목동 중학생 수학과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EB%AA%A9%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</link>
<description><![CDATA[목동 학군 맞춤 1:1 개념 정밀 코칭]]></description>
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
<guid>https://aeseo.cloud/%EB%AA%A9%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</guid>
<title><![CDATA[서울 고등 국어 과외 · 도곡동 고등학생 국어과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EB%8F%84%EA%B3%A1%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EA%B5%AD%EC%96%B4</link>
<description><![CDATA[서울 고등 국어 과외 및 도곡동 관내 학교 내신 기출 분석, 1:1 방문·화상 무료 시범수업 안내]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/%EB%8F%84%EA%B3%A1%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EA%B5%AD%EC%96%B4</guid>
</item>
<item>
<title><![CDATA[서울 초등 과학 과외 · 삼성동 초등학생 과학과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EC%82%BC%EC%84%B1%EB%8F%99/%EC%B4%88%EB%93%B1%ED%95%99%EC%83%9D/%EA%B3%BC%ED%95%99</link>
<description><![CDATA[서울 초등 과학 과외 및 삼성동 관내 학교 내신 기출 분석, 1:1 방문·화상 무료 시범수업 안내]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/%EC%82%BC%EC%84%B1%EB%8F%99/%EC%B4%88%EB%93%B1%ED%95%99%EC%83%9D/%EA%B3%BC%ED%95%99</guid>
</item>
<item>
<title><![CDATA[서울 중등 사회 과외 · 세곡동 중학생 사회과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EC%84%B8%EA%B3%A1%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%82%AC%ED%9A%8C</link>
<description><![CDATA[서울 중등 사회 과외 및 세곡동 관내 학교 내신 기출 분석, 1:1 방문·화상 무료 시범수업 안내]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/%EC%84%B8%EA%B3%A1%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%82%AC%ED%9A%8C</guid>
</item>
<item>
<title><![CDATA[서울 고등 수학 과외 · 수서동 고등학생 수학과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EC%88%98%EC%84%9C%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</link>
<description><![CDATA[서울 고등 수학 과외 및 수서동 관내 학교 내신 기출 분석, 1:1 방문·화상 무료 시범수업 안내]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/%EC%88%98%EC%84%9C%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</guid>
</item>
<item>
<title><![CDATA[서울 초등 영어 과외 · 신사동 초등학생 영어과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EC%8B%A0%EC%82%AC%EB%8F%99/%EC%B4%88%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</link>
<description><![CDATA[서울 초등 영어 과외 및 신사동 관내 학교 내신 기출 분석, 1:1 방문·화상 무료 시범수업 안내]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/%EC%8B%A0%EC%82%AC%EB%8F%99/%EC%B4%88%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</guid>
</item>
<item>
<title><![CDATA[서울 중등 국어 과외 · 압구정동 중학생 국어과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EC%95%95%EA%B5%AC%EC%A0%95%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EA%B5%AD%EC%96%B4</link>
<description><![CDATA[서울 중등 국어 과외 및 압구정동 관내 학교 내신 기출 분석, 1:1 방문·화상 무료 시범수업 안내]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/%EC%95%95%EA%B5%AC%EC%A0%95%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EA%B5%AD%EC%96%B4</guid>
</item>
<item>
<title><![CDATA[서울 고등 과학 과외 · 일원동 고등학생 과학과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EC%9D%BC%EC%9B%90%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EA%B3%BC%ED%95%99</link>
<description><![CDATA[서울 고등 과학 과외 및 일원동 관내 학교 내신 기출 분석, 1:1 방문·화상 무료 시범수업 안내]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/%EC%9D%BC%EC%9B%90%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EA%B3%BC%ED%95%99</guid>
</item>
<item>
<title><![CDATA[서울 초등 사회 과외 · 자곡동 초등학생 사회과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EC%9E%90%EA%B3%A1%EB%8F%99/%EC%B4%88%EB%93%B1%ED%95%99%EC%83%9D/%EC%82%AC%ED%9A%8C</link>
<description><![CDATA[서울 초등 사회 과외 및 자곡동 관내 학교 내신 기출 분석, 1:1 방문·화상 무료 시범수업 안내]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/%EC%9E%90%EA%B3%A1%EB%8F%99/%EC%B4%88%EB%93%B1%ED%95%99%EC%83%9D/%EC%82%AC%ED%9A%8C</guid>
</item>
<item>
<title><![CDATA[서울 중등 수학 과외 · 청담동 중학생 수학과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EC%B2%AD%EB%8B%B4%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</link>
<description><![CDATA[서울 중등 수학 과외 및 청담동 관내 학교 내신 기출 분석, 1:1 방문·화상 무료 시범수업 안내]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/%EC%B2%AD%EB%8B%B4%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</guid>
</item>
<item>
<title><![CDATA[서울 고등 영어 과외 · 강일동 고등학생 영어과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EA%B0%95%EC%9D%BC%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</link>
<description><![CDATA[서울 고등 영어 과외 및 강일동 관내 학교 내신 기출 분석, 1:1 방문·화상 무료 시범수업 안내]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/%EA%B0%95%EC%9D%BC%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</guid>
</item>
<item>
<title><![CDATA[서울 초등 국어 과외 · 고덕동 초등학생 국어과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EA%B3%A0%EB%8D%95%EB%8F%99/%EC%B4%88%EB%93%B1%ED%95%99%EC%83%9D/%EA%B5%AD%EC%96%B4</link>
<description><![CDATA[서울 초등 국어 과외 및 고덕동 관내 학교 내신 기출 분석, 1:1 방문·화상 무료 시범수업 안내]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/%EA%B3%A0%EB%8D%95%EB%8F%99/%EC%B4%88%EB%93%B1%ED%95%99%EC%83%9D/%EA%B5%AD%EC%96%B4</guid>
</item>
<item>
<title><![CDATA[서울 중등 과학 과외 · 길동 중학생 과학과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EA%B8%B8%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EA%B3%BC%ED%95%99</link>
<description><![CDATA[서울 중등 과학 과외 및 길동 관내 학교 내신 기출 분석, 1:1 방문·화상 무료 시범수업 안내]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/%EA%B8%B8%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EA%B3%BC%ED%95%99</guid>
</item>
<item>
<title><![CDATA[서울 고등 사회 과외 · 둔촌동 고등학생 사회과외 1:1 맞춤 수업]]></title>
<link>https://aeseo.cloud/%EB%91%94%EC%B4%8C%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%82%AC%ED%9A%8C</link>
<description><![CDATA[서울 고등 사회 과외 및 둔촌동 관내 학교 내신 기출 분석, 1:1 방문·화상 무료 시범수업 안내]]></description>
<pubDate>Mon, 09 Nov 2026 01:00:00 GMT</pubDate>
<guid>https://aeseo.cloud/%EB%91%94%EC%B4%8C%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%82%AC%ED%9A%8C</guid>
</item>
</channel>
</rss>
</rss>
File diff suppressed because it is too large Load Diff
+3090 -3396
View File
File diff suppressed because it is too large Load Diff
+51
View File
@@ -0,0 +1,51 @@
import regionsData from '../../data/regions.json'
export default defineEventHandler((event) => {
const config = useRuntimeConfig()
const baseUrl = config.public.siteDomain || 'https://aeseo.cloud'
const list = regionsData.list as Array<{ sido: string, sigungu: string, dong: string }>
const uniqueDongs = Array.from(new Set(list.map(r => r.dong).filter(Boolean)))
const today = new Date().toISOString().split('T')[0]
const subjects = ['수학', '영어', '국어', '과학', '사회']
const grades = ['초등학생', '중학생', '고등학생']
const subjectImages: Record<string, string> = {
'수학': `${baseUrl}/img/math-tutoring.png`,
'영어': `${baseUrl}/img/english-tutoring.png`,
'국어': `${baseUrl}/img/korean-tutoring.png`,
'과학': `${baseUrl}/img/science-tutoring.png`,
'사회': `${baseUrl}/img/social-studies-tutoring.png`
}
let xml = `<?xml version="1.0" encoding="UTF-8"?>\n`
xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">\n`
// 메인
xml += ` <url>\n <loc>${baseUrl}/</loc>\n <lastmod>${today}</lastmod>\n <changefreq>daily</changefreq>\n <priority>1.0</priority>\n`
xml += ` <image:image><image:loc>${baseUrl}/img/og-main.png</image:loc></image:image>\n`
xml += ` <image:image><image:loc>${baseUrl}/img/math-tutoring.png</image:loc></image:image>\n`
xml += ` <image:image><image:loc>${baseUrl}/img/english-tutoring.png</image:loc></image:image>\n`
xml += ` <image:image><image:loc>${baseUrl}/img/korean-tutoring.png</image:loc></image:image>\n`
xml += ` <image:image><image:loc>${baseUrl}/img/science-tutoring.png</image:loc></image:image>\n`
xml += ` <image:image><image:loc>${baseUrl}/img/social-studies-tutoring.png</image:loc></image:image>\n`
xml += ` </url>\n`
// 중복 제거된 동별 주요 과목 및 학년 URL 생성 (슬래시 라우터 구조 통일)
uniqueDongs.forEach(dong => {
// 1. 동 대표
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(dong)}</loc>\n <lastmod>${today}</lastmod>\n <changefreq>weekly</changefreq>\n <priority>0.8</priority>\n <image:image><image:loc>${baseUrl}/img/math-tutoring.png</image:loc></image:image>\n </url>\n`
// 2. 동/학년/과목 조합
grades.forEach(g => {
subjects.forEach(sub => {
const imgLoc = subjectImages[sub] || `${baseUrl}/img/math-tutoring.png`
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(dong)}/${encodeURIComponent(g)}/${encodeURIComponent(sub)}</loc>\n <lastmod>${today}</lastmod>\n <changefreq>weekly</changefreq>\n <priority>0.7</priority>\n <image:image><image:loc>${imgLoc}</image:loc></image:image>\n </url>\n`
})
})
})
xml += `</urlset>`
setHeader(event, 'content-type', 'application/xml; charset=utf-8')
return xml
})
+16 -29
View File
@@ -4,8 +4,11 @@ export default defineEventHandler((event) => {
const config = useRuntimeConfig()
const baseUrl = config.public.siteDomain || 'https://aeseo.cloud'
const list = regionsData.list as Array<{ sido: string, sigungu: string, dong: string }>
const uniqueDongs = Array.from(new Set(list.map(r => r.dong).filter(Boolean)))
const today = new Date().toISOString().split('T')[0]
const subjects = ['수학', '영어', '국어', '과학', '사회']
const grades = ['초등학생', '중학생', '고등학생']
const subjectImages: Record<string, string> = {
'수학': `${baseUrl}/img/math-tutoring.png`,
'영어': `${baseUrl}/img/english-tutoring.png`,
@@ -13,46 +16,30 @@ export default defineEventHandler((event) => {
'과학': `${baseUrl}/img/science-tutoring.png`,
'사회': `${baseUrl}/img/social-studies-tutoring.png`
}
const subjects = ['수학', '영어', '국어', '과학', '사회']
const grades = ['초등학생', '중학생', '고등학생']
let xml = `<?xml version="1.0" encoding="UTF-8"?>\n`
xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">\n`
// 메인 (대표 이미지 + 5대 과목 이미지 모두 포함)
xml += ` <url>\n`
xml += ` <loc>${baseUrl}/</loc>\n`
xml += ` <lastmod>${today}</lastmod>\n`
xml += ` <changefreq>daily</changefreq>\n`
xml += ` <priority>1.0</priority>\n`
// 메인
xml += ` <url>\n <loc>${baseUrl}/</loc>\n <lastmod>${today}</lastmod>\n <changefreq>daily</changefreq>\n <priority>1.0</priority>\n`
xml += ` <image:image><image:loc>${baseUrl}/img/og-main.png</image:loc></image:image>\n`
subjects.forEach(sub => {
xml += ` <image:image><image:loc>${subjectImages[sub]}</image:loc></image:image>\n`
})
xml += ` <image:image><image:loc>${baseUrl}/img/math-tutoring.png</image:loc></image:image>\n`
xml += ` <image:image><image:loc>${baseUrl}/img/english-tutoring.png</image:loc></image:image>\n`
xml += ` <image:image><image:loc>${baseUrl}/img/korean-tutoring.png</image:loc></image:image>\n`
xml += ` <image:image><image:loc>${baseUrl}/img/science-tutoring.png</image:loc></image:image>\n`
xml += ` <image:image><image:loc>${baseUrl}/img/social-studies-tutoring.png</image:loc></image:image>\n`
xml += ` </url>\n`
// 동별 주요 과목 및 학년 URL 생성
list.forEach(r => {
// 중복 제거된 동별 주요 과목 및 학년 URL 생성 (슬래시 라우터 구조 통일)
uniqueDongs.forEach(dong => {
// 1. 동 대표
xml += ` <url>\n`
xml += ` <loc>${baseUrl}/${encodeURIComponent(r.dong)}</loc>\n`
xml += ` <lastmod>${today}</lastmod>\n`
xml += ` <changefreq>weekly</changefreq>\n`
xml += ` <priority>0.8</priority>\n`
xml += ` <image:image><image:loc>${baseUrl}/img/og-main.png</image:loc></image:image>\n`
xml += ` <image:image><image:loc>${baseUrl}/img/math-tutoring.png</image:loc></image:image>\n`
xml += ` </url>\n`
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(dong)}</loc>\n <lastmod>${today}</lastmod>\n <changefreq>weekly</changefreq>\n <priority>0.8</priority>\n <image:image><image:loc>${baseUrl}/img/math-tutoring.png</image:loc></image:image>\n </url>\n`
// 2. 동/학년/과목 대표 조합
// 2. 동/학년/과목 조합
grades.forEach(g => {
subjects.forEach(sub => {
xml += ` <url>\n`
xml += ` <loc>${baseUrl}/${encodeURIComponent(r.dong)}/${encodeURIComponent(g)}/${encodeURIComponent(sub)}</loc>\n`
xml += ` <lastmod>${today}</lastmod>\n`
xml += ` <changefreq>weekly</changefreq>\n`
xml += ` <priority>0.7</priority>\n`
xml += ` <image:image><image:loc>${subjectImages[sub]}</image:loc></image:image>\n`
xml += ` </url>\n`
const imgLoc = subjectImages[sub] || `${baseUrl}/img/math-tutoring.png`
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(dong)}/${encodeURIComponent(g)}/${encodeURIComponent(sub)}</loc>\n <lastmod>${today}</lastmod>\n <changefreq>weekly</changefreq>\n <priority>0.7</priority>\n <image:image><image:loc>${imgLoc}</image:loc></image:image>\n </url>\n`
})
})
})
+13 -7
View File
@@ -113,30 +113,35 @@ export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams
} else if (typeof slugInput === 'string' && slugInput.trim()) {
tokens = decodeURIComponent(slugInput).split(/[-_\s/]+/)
}
tokens = tokens.map(t => t.trim()).filter(Boolean)
tokens = tokens.map(t => t.trim()).filter(t => Boolean(t) && !/^index\.html?$/i.test(t))
let matchedRegion: RegionInfo | null = null
let matchedTokenIdx = -1
let detectedGrade = '중학생'
let detectedGradeShort = '중등'
let detectedSubjectKey = 'english'
let detectedSubjectName = '영어'
let detectedSubjectKey = 'math'
let detectedSubjectName = '수학'
let detectedTerm = '과외'
// 1. 토큰들 중 동 이름 매칭
for (const token of tokens) {
for (let i = 0; i < tokens.length; i++) {
const token = tokens[i]
const reg = getRegionByDong(token)
if (reg) {
matchedRegion = reg
matchedTokenIdx = i
break
}
}
// 2. 동 이름이 토큰에 없으면 전체 리스트에서 부분 일치 검색
if (!matchedRegion && tokens.length > 0) {
for (const token of tokens) {
for (let i = 0; i < tokens.length; i++) {
const token = tokens[i]
const found = (regionsData.list as RegionInfo[]).find(r => token.includes(r.dong) || (token.length >= 2 && r.dong.includes(token)))
if (found) {
matchedRegion = found
matchedTokenIdx = i
break
}
}
@@ -152,9 +157,10 @@ export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams
}
}
// 3. 학년 추출
// 3. 학년 추출 (동 이름 토큰을 제외한 나머지 토큰에서만 검색하여 '고등동', '문학동' 등 별칭 충돌 원천 차단)
let hasExplicitGrade = false
const fullText = tokens.join(' ')
const remainingTokens = tokens.filter((_, idx) => idx !== matchedTokenIdx)
const fullText = remainingTokens.join(' ')
for (const g of GRADES_LIST) {
if (g.aliases.some(a => fullText.includes(a))) {
detectedGrade = g.name
+10 -5
View File
@@ -1,5 +1,5 @@
import type { ParsedRouteParams } from './dataHelper'
import { getShortRegionName } from './dataHelper'
import { getShortRegionName, getShortSido } from './dataHelper'
const SUBJECT_IMAGE_MAP: Record<string, string> = {
math: '/img/math-tutoring.png',
@@ -22,18 +22,23 @@ const GRADE_LIST = ['초등학생', '중학생', '고등학생']
export function generateSeoMeta(parsed: ParsedRouteParams, siteName = '로열클래스 1:1 과외', siteDomain = 'https://aeseo.cloud') {
const { sido, sigungu, dong, shortRegionName, grade, subjectKey, subjectName, isRegionOnly } = parsed
const shortSido = (sido || '').replace(/특별시|광역시|특별자치시|도/g, '').trim() || '서울'
const shortSido = getShortSido(sido) || '서울'
const gradeShort = parsed.gradeShort || (grade === '초등학생' ? '초등' : grade === '고등학생' ? '고등' : '중등')
const regionTitle = shortRegionName || getShortRegionName(sido, dong)
const regionTitle = shortRegionName || getShortRegionName(sido, dong, sigungu)
const subjectImg = SUBJECT_IMAGE_MAP[subjectKey] || '/img/math-tutoring.png'
const dongHash = Array.from(dong || '').reduce((acc, ch) => acc + ch.charCodeAt(0), 0)
const baseSubjects = ['수학', '영어', '국어', '과학', '사회']
const rotatedSubjects = baseSubjects.map((_, i) => baseSubjects[(dongHash + i) % baseSubjects.length])
const rotatedSubText = rotatedSubjects.map(s => `${dong}${s}과외선생님`).join(', ')
const pageTitle = isRegionOnly
? `${shortSido} 중등 수학 과외 · ${shortSido} 중등 과외 | ${regionTitle} 초·중·고 1:1 맞춤 과외`
: `${shortSido} ${gradeShort} ${subjectName} 과외 · ${regionTitle} ${grade} ${subjectName}과외 | ${shortSido} ${gradeShort} 과외 1:1 매칭`
const pageDescription = isRegionOnly
? `${shortSido} 중등 수학 과외, ${shortSido} 중등 과외, ${dong} 중등 수학 과외 전문 ${siteName}! ${regionTitle} 초등·중등·고등 국영수사과 1:1 맞춤 과외와 검증된 전문 선생님 무료 시범수업, 과외비 비교를 확인하세요.`
: `${shortSido} ${gradeShort} ${subjectName} 과외, ${shortSido} ${gradeShort} 과외, ${dong} ${gradeShort} ${subjectName} 과외 전문 ${siteName}! ${regionTitle} ${grade} ${subjectName} 1:1 방문·화상 맞춤 수업으로 내신·수능 성적 향상을 책임집니다. 과외비 투명 공개 및 무료 시범수업 신청하세요.`
? `${shortSido} 중등 수학 과외, ${shortSido} 중등 과외, ${dong} 중등 수학 과외 전문 ${siteName}! ${regionTitle} 초등·중등·고등 국영수사과 1:1 맞춤 과외와 검증된 전문 선생님 무료 시범수업, 과외비 비교(${rotatedSubText})를 확인하세요.`
: `${shortSido} ${gradeShort} ${subjectName} 과외, ${shortSido} ${gradeShort} 과외, ${dong} ${gradeShort} ${subjectName} 과외 전문 ${siteName}! ${regionTitle} ${grade} ${subjectName} 1:1 방문·화상 맞춤 수업으로 내신·수능 성적 향상을 책임집니다. 과외비 투명 공개 및 무료 시범수업(${rotatedSubText})을 신청하세요.`
const dongUrl = `${siteDomain}/${encodeURIComponent(dong)}`
const canonicalUrl = isRegionOnly