mirror of
https://github.com/headporter81/specialsource-homepage-frontend.git
synced 2026-08-08 15:21:11 +09:00
Compare commits
2
Commits
911f1a171d
...
f65ea396b6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f65ea396b6 | ||
|
|
4bbc9380f3 |
+80
-5
@@ -5,6 +5,10 @@
|
||||
<span class="status-dot" :class="{ 'secure-mode': isLoggedIn }"></span>
|
||||
<span class="brand">SPECIALSOURCE.SYSTEM</span>
|
||||
|
||||
<span :class="['server-badge', currentServerSource]">
|
||||
[{{ currentServerSourceDisplay }}]
|
||||
</span>
|
||||
|
||||
<div v-if="isLoggedIn" class="nav-stats">
|
||||
[LIVE:<span class="pulse-text">{{ activeNow }}</span>|TODAY:{{ todayUnique }}]
|
||||
</div>
|
||||
@@ -171,6 +175,9 @@ const todayUnique = ref(0);
|
||||
const activeNow = ref(0);
|
||||
let analyticsTimer = null;
|
||||
|
||||
// 🟢 [NEW] NAS 생존 여부 실시간 판단용 반응형 변수
|
||||
const isNasOnline = ref(true);
|
||||
|
||||
const menuItems = [
|
||||
{ id: 'main', name: 'HOME' },
|
||||
{ id: 'youtube', name: 'YOUTUBE' },
|
||||
@@ -181,6 +188,36 @@ const menuItems = [
|
||||
|
||||
const isLoggedIn = computed(() => !!authToken.value);
|
||||
|
||||
// 🟢 [NEW] 현재 활성화된 서버 판별 엔진 (시간 + API 생존 여부 조합)
|
||||
const currentServerSource = computed(() => {
|
||||
const currentHour = new Date().getUTCHours() + 9; // 한국 표준시(KST) 보정
|
||||
const localHour = currentHour % 24;
|
||||
|
||||
// 1. 밤 12시 ~ 아침 8시 사이 (워커가 퇴근시키고 파이어베이스로 무조건 우회하는 정기 백업 시간대)
|
||||
if (localHour >= 0 && localHour < 8) {
|
||||
return 'firebase_backup';
|
||||
}
|
||||
|
||||
// 2. 낮 시간대인데 NAS 통신이 끊겼거나 오류가 나서 파이어베이스 우회 대피소로 긴급 이동된 상태
|
||||
if (!isNasOnline.value) {
|
||||
return 'firebase_failover';
|
||||
}
|
||||
|
||||
// 3. 낮 시간대에 NAS 서버가 건강하게 서비스를 전달하고 있는 최고 권한 메인 노드 상태
|
||||
return 'nas_main';
|
||||
});
|
||||
|
||||
// 🟢 [NEW] 터미널 콘솔 감성의 문자열 맵핑 출력 기믹
|
||||
const currentServerSourceDisplay = computed(() => {
|
||||
if (currentServerSource.value === 'firebase_backup') {
|
||||
return 'NODE:FB_NIGHT_MODE';
|
||||
}
|
||||
if (currentServerSource.value === 'firebase_failover') {
|
||||
return 'NODE:FB_FAILOVER';
|
||||
}
|
||||
return 'NODE:NAS_ACTIVE';
|
||||
});
|
||||
|
||||
const rawAscii = `
|
||||
███████╗██████╗ ███████╗ ██████╗██╗ █████╗ ██╗
|
||||
██╔════╝██╔══██╗██╔════╝██╔════╝██║██╔══██╗██║
|
||||
@@ -205,6 +242,7 @@ const formattedAscii = computed(() => {
|
||||
return rawAscii.replace(/ /g, '<span class="bg-block">█</span>');
|
||||
});
|
||||
|
||||
// 🟢 [MODIFY] 30초 간격으로 스펙을 긁어올 때 NAS가 건강하게 응답하는지 체크하는 유효성 로직 추가
|
||||
const fetchAnalyticsData = async () => {
|
||||
try {
|
||||
const apiBaseUrl = import.meta.env.VITE_API_URL || '';
|
||||
@@ -212,9 +250,11 @@ const fetchAnalyticsData = async () => {
|
||||
if (res.data) {
|
||||
todayUnique.value = res.data.todayUnique || 0;
|
||||
activeNow.value = res.data.activeNow || 0;
|
||||
isNasOnline.value = true; // 🟢 정상 동작 확인 -> 'NODE:NAS_ACTIVE' 출력 보장
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("관제 통계 데이터 로드 실패:", err);
|
||||
isNasOnline.value = false; // 🟢 에러 발생 시 자동으로 비상망 배지('NODE:FB_FAILOVER')로 교체
|
||||
}
|
||||
};
|
||||
|
||||
@@ -374,12 +414,10 @@ onMounted(() => {
|
||||
'specialsource': function () { this.echo('SPECIALSOURCE Established 2021.01.'); },
|
||||
'email': function () { this.echo('specialsource.company@gmail.com'); },
|
||||
|
||||
// 🟢 [NEW] 리얼타임 레이아웃 텍스트 순차 타이핑 프린팅 기믹 함수 구현
|
||||
'status': function () {
|
||||
const term = this;
|
||||
term.pause(); // 타이핑 진행 중엔 추가 명령어 입력을 잠금(인프라 보호 감성)
|
||||
term.pause();
|
||||
|
||||
// 프린팅할 덤프 행렬 배열화
|
||||
const lines = [
|
||||
"============================================",
|
||||
" 📟 SPECIALSOURCE TRAFFIC ARCHITECTURE",
|
||||
@@ -393,14 +431,13 @@ onMounted(() => {
|
||||
term.echo("[SYS] EXTRACTING POSTGRESQL METADATA... SNAPSHOT READY.");
|
||||
|
||||
let index = 0;
|
||||
// 110ms 간격으로 스태거드 라인 출력 기믹 기동
|
||||
const typingInterval = setInterval(() => {
|
||||
if (index < lines.length) {
|
||||
term.echo(lines[index]);
|
||||
index++;
|
||||
} else {
|
||||
clearInterval(typingInterval);
|
||||
term.resume(); // 타이핑 종료 후 유저 입력 언락
|
||||
term.resume();
|
||||
}
|
||||
}, 110);
|
||||
},
|
||||
@@ -434,6 +471,7 @@ onUnmounted(() => {
|
||||
.contact-form,
|
||||
.theme-selector,
|
||||
.nav-stats,
|
||||
.server-badge,
|
||||
:deep(.terminal),
|
||||
:deep(.terminal span) {
|
||||
font-family: 'JetBrains Mono', monospace !important;
|
||||
@@ -513,6 +551,37 @@ onUnmounted(() => {
|
||||
box-shadow: 0 0 8px var(--tui-glow);
|
||||
}
|
||||
|
||||
/* 🟢 [NEW] 터미널 감성의 실시간 감지 서버 배지 스타일링 */
|
||||
.server-badge {
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
padding: 3px 8px;
|
||||
border: 1px solid currentColor;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
letter-spacing: 1px;
|
||||
border-radius: 2px;
|
||||
transition: 0.3s;
|
||||
}
|
||||
/* NAS 활성화 상태 (그린 계열/현재 테마 컬러 적용) */
|
||||
.server-badge.nas_main {
|
||||
color: var(--tui-color);
|
||||
text-shadow: 0 0 5px var(--tui-glow);
|
||||
border-color: var(--tui-border);
|
||||
}
|
||||
/* 정기 야간 Firebase 백업 작동 상태 (호박색) */
|
||||
.server-badge.firebase_backup {
|
||||
color: #ffb000;
|
||||
text-shadow: 0 0 5px rgba(255, 176, 0, 0.6);
|
||||
border-color: rgba(255, 176, 0, 0.3);
|
||||
}
|
||||
/* 대낮 비상 통신장애 Firebase 백업 가동 상태 (강력한 레드 경고 & 점멸) */
|
||||
.server-badge.firebase_failover {
|
||||
color: #ff3b3b;
|
||||
text-shadow: 0 0 8px #ff3b3b;
|
||||
border-color: rgba(255, 59, 59, 0.4);
|
||||
animation: badgeBlink 1.5s infinite ease-in-out;
|
||||
}
|
||||
|
||||
/* --- GNB --- */
|
||||
.auth-nav {
|
||||
display: flex;
|
||||
@@ -749,6 +818,12 @@ iframe { width: 100%; height: 180px; border-radius: 4px; }
|
||||
50% { opacity: 1; text-shadow: 0 0 8px var(--tui-glow); }
|
||||
}
|
||||
|
||||
/* 🟢 [NEW] 비상 Failover 점멸 애니메이션 */
|
||||
@keyframes badgeBlink {
|
||||
0%, 100% { opacity: 0.6; box-shadow: 0 0 5px rgba(255, 59, 59, 0.2); }
|
||||
50% { opacity: 1; box-shadow: 0 0 15px rgba(255, 59, 59, 0.6); text-shadow: 0 0 12px #ff3b3b; }
|
||||
}
|
||||
|
||||
/* 일회성 사이버 글리치 키프레임 */
|
||||
@keyframes once-cyber-glitch-wobble {
|
||||
0%, 25% { transform: translate(0) scale(1) skewX(0deg); color: var(--tui-color) !important; text-shadow: 0 0 8px var(--tui-glow) !important; opacity: 1; }
|
||||
|
||||
Reference in New Issue
Block a user