commit d46843bf268708e064ae42e9388e39cd0887c8af Author: ZioCI Date: Sat May 30 18:41:49 2026 +0900 feat: admin system diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..877cd0c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# Backend +backend/target/ +backend/data/ +backend/*.db + +# Frontend +frontend/node_modules/ +frontend/dist/ +frontend/.vite/ + +# Secrets / OS +.env +.env.local +*.log +.DS_Store +Thumbs.db diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000..38ed33fa --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,97 @@ +pipeline { + agent any + + environment { + DEPLOY_DIR = '/var/www/zioinfo' + APP_DIR = '/opt/zioinfo/app' + JAVA_HOME = '/usr/lib/jvm/java-21-openjdk-amd64' + MVN = '/usr/bin/mvn' + NODE_HOME = '/usr/bin' + } + + options { + buildDiscarder(logRotator(numToKeepStr: '5')) + timeout(time: 20, unit: 'MINUTES') + } + + stages { + stage('Checkout') { + steps { + echo "브랜치: ${env.GIT_BRANCH ?: 'main'} | 커밋: ${env.GIT_COMMIT?.take(7) ?: '-'}" + checkout scm + } + } + + stage('Frontend Build') { + steps { + dir('frontend') { + sh ''' + echo "=== [1/3] React 빌드 ===" + npm ci --legacy-peer-deps --prefer-offline 2>/dev/null || npm install --legacy-peer-deps + npm run build + echo "빌드 결과: $(ls ../backend/src/main/resources/static/assets/ | wc -l) 파일" + ''' + } + } + } + + stage('Backend Build') { + steps { + dir('backend') { + sh ''' + echo "=== [2/3] Spring Boot 빌드 ===" + ${MVN} clean package -DskipTests -q + JAR=$(find target -name "*.jar" ! -name "*sources*" | head -1) + echo "JAR: $JAR ($(du -sh $JAR | cut -f1))" + ''' + } + } + } + + stage('Deploy') { + steps { + sh ''' + echo "=== [3/3] 배포 ===" + JAR=$(find backend/target -name "*.jar" ! -name "*sources*" | head -1) + + # 앱 디렉터리 확인 + mkdir -p ${APP_DIR} ${DEPLOY_DIR} + + # JAR 배포 + cp "$JAR" ${APP_DIR}/app.jar + + # React 정적 파일 배포 + cp -r backend/src/main/resources/static/. ${DEPLOY_DIR}/ + + # Spring Boot 서비스 재시작 + systemctl restart zioinfo || true + sleep 4 + + # 헬스체크 + for i in 1 2 3 4 5; do + HTTP=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/api/company 2>/dev/null) + if [ "$HTTP" = "200" ]; then + echo "배포 성공 (Spring Boot HTTP $HTTP)" + exit 0 + fi + echo "헬스체크 ${i}/5 대기중 (HTTP: $HTTP)..." + sleep 3 + done + echo "경고: Spring Boot 응답 없음 — 서비스 상태 확인 필요" + ''' + } + } + } + + post { + success { + echo "✅ 배포 완료: ${currentBuild.displayName} (${currentBuild.durationString})" + } + failure { + echo "❌ 배포 실패: ${currentBuild.displayName} — 로그 확인 필요" + } + always { + cleanWs(cleanWhenNotBuilt: false, cleanWhenSuccess: false) + } + } +} diff --git a/backend/.mvn/wrapper/maven-wrapper.properties b/backend/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..e70e7bc8 --- /dev/null +++ b/backend/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/backend/pom.xml b/backend/pom.xml new file mode 100644 index 00000000..fb87fb6b --- /dev/null +++ b/backend/pom.xml @@ -0,0 +1,126 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.2.5 + + + + kr.co.zioinfo + zioinfo-web + 1.0.0 + jar + ZioInfo Web + (주)지오정보기술 기업 홈페이지 + + + 17 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + org.xerial + sqlite-jdbc + 3.45.3.0 + + + + org.hibernate.orm + hibernate-community-dialects + + + + + com.mysql + mysql-connector-j + runtime + true + + + + + org.springframework.boot + spring-boot-starter-validation + + + + + org.springframework.boot + spring-boot-starter-mail + + + + + org.springframework.boot + spring-boot-starter-security + + + + + io.jsonwebtoken + jjwt-api + 0.12.3 + + + io.jsonwebtoken + jjwt-impl + 0.12.3 + runtime + + + io.jsonwebtoken + jjwt-jackson + 0.12.3 + runtime + + + + + org.projectlombok + lombok + true + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + diff --git a/backend/src/main/java/kr/co/zioinfo/web/ZioinfoWebApplication.java b/backend/src/main/java/kr/co/zioinfo/web/ZioinfoWebApplication.java new file mode 100644 index 00000000..a171330a --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/ZioinfoWebApplication.java @@ -0,0 +1,13 @@ +package kr.co.zioinfo.web; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + +@SpringBootApplication +@EnableJpaAuditing +public class ZioinfoWebApplication { + public static void main(String[] args) { + SpringApplication.run(ZioinfoWebApplication.class, args); + } +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/config/DataInitializer.java b/backend/src/main/java/kr/co/zioinfo/web/config/DataInitializer.java new file mode 100644 index 00000000..bf8114ac --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/config/DataInitializer.java @@ -0,0 +1,97 @@ +package kr.co.zioinfo.web.config; + +import kr.co.zioinfo.web.model.*; +import kr.co.zioinfo.web.repository.*; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.CommandLineRunner; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; +import java.time.LocalDate; + +@Component +@RequiredArgsConstructor +public class DataInitializer implements CommandLineRunner { + + private final NewsRepository newsRepo; + private final AdminUserRepository adminUserRepo; + private final RecruitRepository recruitRepo; + private final PasswordEncoder passwordEncoder; + + @Override + public void run(String... args) { + initAdmin(); + initNews(); + initRecruits(); + } + + private void initAdmin() { + if (adminUserRepo.existsByUsername("admin")) return; + adminUserRepo.save(AdminUser.builder() + .username("admin") + .password(passwordEncoder.encode("Admin@2026!")) + .displayName("관리자") + .email("admin@zioinfo.co.kr") + .enabled(true) + .build()); + } + + private void initNews() { + if (newsRepo.count() > 0) return; + + newsRepo.save(News.builder() + .title("GUARDiA ITSM 2.0 정식 출시 — AI 기반 인프라 자율 운영 플랫폼") + .category("보도자료") + .summary("(주)지오정보기술이 공공기관 레거시 인프라 자동화를 위한 GUARDiA ITSM 2.0을 정식 출시했습니다.") + .content("GUARDiA ITSM 2.0은 메신저 한 줄 명령으로 에이전트리스 SSH/SFTP 배포·운영을 자동화하는 온프레미스 플랫폼입니다.") + .visible(true).viewCount(128).build()); + + newsRepo.save(News.builder() + .title("2026 공공기관 AI 인프라 혁신 박람회 참가") + .category("공지사항") + .summary("지오정보기술이 2026 공공기관 AI 인프라 혁신 박람회에 참가하여 GUARDiA 솔루션을 선보입니다.") + .content("박람회 기간: 2026년 6월 15일~17일 / 장소: 코엑스 A홀 / 부스: A-215") + .visible(true).viewCount(87).build()); + + newsRepo.save(News.builder() + .title("행정안전부 공공SW 우수제품 선정") + .category("보도자료") + .summary("GUARDiA ITSM이 행정안전부 2026년 공공SW 우수제품으로 선정되었습니다.") + .content("행정안전부는 공공기관 정보화 사업에 적합한 소프트웨어를 심사하여 우수제품을 선정합니다.") + .visible(true).viewCount(214).build()); + + newsRepo.save(News.builder() + .title("특허 등록 — 에이전트리스 레거시 인프라 자동화 방법") + .category("공지사항") + .summary("에이전트 설치 없이 SSH/SFTP 프로토콜만으로 레거시 WAS를 자동화하는 방법에 대한 특허가 등록되었습니다.") + .content("특허명: 에이전트리스 레거시 인프라 자동화 시스템 및 방법\n등록번호: 10-2026-XXXXXXX") + .visible(true).viewCount(41).build()); + } + + private void initRecruits() { + if (recruitRepo.count() > 0) return; + + recruitRepo.save(Recruit.builder() + .title("백엔드 개발자 (Java/Spring Boot)") + .department("개발팀").jobType("정규직") + .description("- GUARDiA ITSM 백엔드 API 개발\n- 성능 최적화 및 코드 리뷰\n- 공공기관 SI 프로젝트 참여") + .requirements("- Spring Boot 실무 경력 3년 이상\n- JPA/Hibernate 경험\n- RESTful API 설계 능력") + .preferred("- 공공기관 프로젝트 경험\n- MSA 아키텍처 이해\n- 보안 코딩 경험") + .deadline(LocalDate.of(2026, 6, 30)).headcount(2).active(true).build()); + + recruitRepo.save(Recruit.builder() + .title("프론트엔드 개발자 (React)") + .department("개발팀").jobType("정규직") + .description("- React SPA 개발 및 유지보수\n- 홈페이지 및 관리자 페이지 개발\n- UI/UX 개선") + .requirements("- React 실무 경력 2년 이상\n- JavaScript/TypeScript 능숙\n- CSS 레이아웃 및 반응형 웹 경험") + .preferred("- 공공기관 프로젝트 경험\n- 데이터 시각화 경험 (Chart.js 등)") + .deadline(LocalDate.of(2026, 6, 30)).headcount(1).active(true).build()); + + recruitRepo.save(Recruit.builder() + .title("인프라 엔지니어 (Linux/DevOps)") + .department("인프라팀").jobType("정규직") + .description("- 공공기관 서버 인프라 구축 및 운영\n- CI/CD 파이프라인 관리\n- 보안 취약점 점검") + .requirements("- Linux 서버 운영 경력 3년 이상\n- Ansible/Terraform 경험\n- 네트워크 기초 지식") + .preferred("- 공공기관 정보보호 인증 자격증 (정보처리기사 등)\n- Kubernetes 경험") + .deadline(LocalDate.of(2026, 7, 31)).headcount(1).active(true).build()); + } +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/config/SecurityConfig.java b/backend/src/main/java/kr/co/zioinfo/web/config/SecurityConfig.java new file mode 100644 index 00000000..ae341ad1 --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/config/SecurityConfig.java @@ -0,0 +1,61 @@ +package kr.co.zioinfo.web.config; + +import kr.co.zioinfo.web.security.JwtAuthFilter; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import java.util.List; + +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +public class SecurityConfig { + + private final JwtAuthFilter jwtAuthFilter; + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + return http + .csrf(AbstractHttpConfigurer::disable) + .cors(cors -> cors.configurationSource(corsConfigurationSource())) + .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests(auth -> auth + .requestMatchers(HttpMethod.POST, "/api/admin/login").permitAll() + .requestMatchers("/api/admin/**").hasRole("ADMIN") + .requestMatchers(HttpMethod.GET, "/api/**").permitAll() + .requestMatchers(HttpMethod.POST, "/api/inquiry").permitAll() + .requestMatchers("/", "/**").permitAll() + .anyRequest().authenticated()) + .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class) + .build(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration cfg = new CorsConfiguration(); + cfg.setAllowedOriginPatterns(List.of("*")); + cfg.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); + cfg.setAllowedHeaders(List.of("*")); + cfg.setAllowCredentials(true); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", cfg); + return source; + } +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/controller/AdminController.java b/backend/src/main/java/kr/co/zioinfo/web/controller/AdminController.java new file mode 100644 index 00000000..bb1cb0a2 --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/controller/AdminController.java @@ -0,0 +1,182 @@ +package kr.co.zioinfo.web.controller; + +import kr.co.zioinfo.web.model.*; +import kr.co.zioinfo.web.repository.*; +import kr.co.zioinfo.web.security.JwtUtil; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.*; +import org.springframework.http.ResponseEntity; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.bind.annotation.*; +import java.util.*; + +@RestController +@RequestMapping("/api/admin") +@RequiredArgsConstructor +public class AdminController { + + private final AdminUserRepository adminUserRepo; + private final NewsRepository newsRepo; + private final InquiryRepository inquiryRepo; + private final RecruitRepository recruitRepo; + private final JwtUtil jwtUtil; + private final PasswordEncoder passwordEncoder; + + // ── 로그인 ──────────────────────────────────────────────── + @PostMapping("/login") + public ResponseEntity login(@RequestBody Map body) { + String username = body.get("username"); + String password = body.get("password"); + + return adminUserRepo.findByUsername(username) + .filter(u -> u.isEnabled() && passwordEncoder.matches(password, u.getPassword())) + .map(u -> ResponseEntity.ok(Map.of( + "token", jwtUtil.generate(u.getUsername()), + "username", u.getUsername(), + "displayName", Optional.ofNullable(u.getDisplayName()).orElse(u.getUsername())))) + .orElse(ResponseEntity.status(401).body(Map.of("message", "아이디 또는 비밀번호가 올바르지 않습니다."))); + } + + // ── 대시보드 통계 ──────────────────────────────────────── + @GetMapping("/dashboard") + public ResponseEntity> dashboard() { + Map stats = new LinkedHashMap<>(); + stats.put("totalNews", newsRepo.count()); + stats.put("visibleNews", newsRepo.countByVisibleTrue()); + stats.put("totalInquiries", inquiryRepo.count()); + stats.put("pendingInquiries", inquiryRepo.countByStatus("PENDING")); + stats.put("totalRecruits", recruitRepo.count()); + stats.put("activeRecruits", recruitRepo.countByActiveTrue()); + stats.put("recentInquiries", inquiryRepo.findTop5ByOrderByCreatedAtDesc()); + stats.put("recentNews", newsRepo.findTop5ByOrderByCreatedAtDesc()); + return ResponseEntity.ok(stats); + } + + // ── 뉴스 관리 ──────────────────────────────────────────── + @GetMapping("/news") + public ResponseEntity> adminNews( + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size) { + return ResponseEntity.ok(newsRepo.findAll( + PageRequest.of(page, size, Sort.by("createdAt").descending()))); + } + + @PostMapping("/news") + public ResponseEntity createNews(@RequestBody News news) { + news.setId(null); + news.setCreatedAt(null); + return ResponseEntity.ok(newsRepo.save(news)); + } + + @PutMapping("/news/{id}") + public ResponseEntity updateNews(@PathVariable Long id, @RequestBody News body) { + return newsRepo.findById(id).map(n -> { + n.setTitle(body.getTitle()); + n.setCategory(body.getCategory()); + n.setContent(body.getContent()); + n.setSummary(body.getSummary()); + n.setThumbnailUrl(body.getThumbnailUrl()); + n.setVisible(body.isVisible()); + return ResponseEntity.ok(newsRepo.save(n)); + }).orElse(ResponseEntity.notFound().build()); + } + + @DeleteMapping("/news/{id}") + public ResponseEntity deleteNews(@PathVariable Long id) { + if (!newsRepo.existsById(id)) return ResponseEntity.notFound().build(); + newsRepo.deleteById(id); + return ResponseEntity.noContent().build(); + } + + @PatchMapping("/news/{id}/visibility") + public ResponseEntity toggleVisibility(@PathVariable Long id) { + return newsRepo.findById(id).map(n -> { + n.setVisible(!n.isVisible()); + return ResponseEntity.ok(newsRepo.save(n)); + }).orElse(ResponseEntity.notFound().build()); + } + + // ── 문의 관리 ──────────────────────────────────────────── + @GetMapping("/inquiries") + public ResponseEntity> adminInquiries( + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size, + @RequestParam(required = false) String status) { + Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending()); + Page result = (status != null && !status.isBlank()) + ? inquiryRepo.findByStatus(status, pageable) + : inquiryRepo.findAll(pageable); + return ResponseEntity.ok(result); + } + + @GetMapping("/inquiries/{id}") + public ResponseEntity getInquiry(@PathVariable Long id) { + return inquiryRepo.findById(id) + .map(ResponseEntity::ok) + .orElse(ResponseEntity.notFound().build()); + } + + @PatchMapping("/inquiries/{id}/status") + public ResponseEntity updateInquiryStatus( + @PathVariable Long id, @RequestBody Map body) { + return inquiryRepo.findById(id).map(i -> { + i.setStatus(body.getOrDefault("status", i.getStatus())); + return ResponseEntity.ok(inquiryRepo.save(i)); + }).orElse(ResponseEntity.notFound().build()); + } + + // ── 채용공고 관리 ──────────────────────────────────────── + @GetMapping("/recruits") + public ResponseEntity> adminRecruits( + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size) { + return ResponseEntity.ok(recruitRepo.findAllByOrderByCreatedAtDesc( + PageRequest.of(page, size))); + } + + @PostMapping("/recruits") + public ResponseEntity createRecruit(@RequestBody Recruit recruit) { + recruit.setId(null); + recruit.setCreatedAt(null); + return ResponseEntity.ok(recruitRepo.save(recruit)); + } + + @PutMapping("/recruits/{id}") + public ResponseEntity updateRecruit(@PathVariable Long id, @RequestBody Recruit body) { + return recruitRepo.findById(id).map(r -> { + r.setTitle(body.getTitle()); + r.setDepartment(body.getDepartment()); + r.setJobType(body.getJobType()); + r.setDescription(body.getDescription()); + r.setRequirements(body.getRequirements()); + r.setPreferred(body.getPreferred()); + r.setDeadline(body.getDeadline()); + r.setHeadcount(body.getHeadcount()); + r.setActive(body.isActive()); + return ResponseEntity.ok(recruitRepo.save(r)); + }).orElse(ResponseEntity.notFound().build()); + } + + @DeleteMapping("/recruits/{id}") + public ResponseEntity deleteRecruit(@PathVariable Long id) { + if (!recruitRepo.existsById(id)) return ResponseEntity.notFound().build(); + recruitRepo.deleteById(id); + return ResponseEntity.noContent().build(); + } + + // ── 비밀번호 변경 ──────────────────────────────────────── + @PutMapping("/password") + public ResponseEntity changePassword( + @RequestBody Map body, + jakarta.servlet.http.HttpServletRequest req) { + String authHeader = req.getHeader("Authorization"); + String username = jwtUtil.extractUsername(authHeader.substring(7)); + return adminUserRepo.findByUsername(username).map(u -> { + if (!passwordEncoder.matches(body.get("currentPassword"), u.getPassword())) + return ResponseEntity.badRequest().body(Map.of("message", "현재 비밀번호가 올바르지 않습니다.")); + u.setPassword(passwordEncoder.encode(body.get("newPassword"))); + adminUserRepo.save(u); + return ResponseEntity.ok(Map.of("message", "비밀번호가 변경되었습니다.")); + }).orElse(ResponseEntity.notFound().build()); + } +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/controller/ApiController.java b/backend/src/main/java/kr/co/zioinfo/web/controller/ApiController.java new file mode 100644 index 00000000..c8a2d87c --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/controller/ApiController.java @@ -0,0 +1,190 @@ +package kr.co.zioinfo.web.controller; + +import kr.co.zioinfo.web.model.Inquiry; +import kr.co.zioinfo.web.model.News; +import kr.co.zioinfo.web.repository.RecruitRepository; +import kr.co.zioinfo.web.service.InquiryService; +import kr.co.zioinfo.web.service.NewsService; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.*; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import jakarta.validation.Valid; +import java.util.*; + +@RestController +@RequestMapping("/api") +@RequiredArgsConstructor +public class ApiController { + + private final NewsService newsService; + private final InquiryService inquiryService; + private final RecruitRepository recruitRepo; + + // ── 회사 정보 ──────────────────────────────────────────────── + @GetMapping("/company") + public ResponseEntity> getCompanyInfo() { + Map info = new LinkedHashMap<>(); + info.put("name", "(주)지오정보기술"); + info.put("ceo", "대표이사"); + info.put("founded", "2000년"); + info.put("address", "서울특별시"); + info.put("phone", "02-000-0000"); + info.put("email", "info@zioinfo.co.kr"); + info.put("business", Arrays.asList( + Map.of("name", "GUARDiA ITSM", "desc", "AI 기반 레거시 인프라 자율 운영 플랫폼"), + Map.of("name", "ERP 솔루션", "desc", "기업 자원관리 시스템"), + Map.of("name", "SI 구축", "desc", "정보화사업 시스템 통합"), + Map.of("name", "IT 인프라", "desc", "인프라 구축 및 운영") + )); + return ResponseEntity.ok(info); + } + + // ── 연혁 ───────────────────────────────────────────────────── + @GetMapping("/history") + public ResponseEntity>> getHistory() { + List> history = new ArrayList<>(); + history.add(Map.of("year", "2026", "events", List.of( + "GUARDiA ITSM v2.0 출시 (AI 자율 운영 플랫폼)", + "공공기관 AI 인프라 자동화 사업 수주" + ))); + history.add(Map.of("year", "2024", "events", List.of( + "GUARDiA ITSM v1.0 개발 완료", + "관공서 레거시 인프라 자동화 특허 출원" + ))); + history.add(Map.of("year", "2022", "events", List.of( + "AI 기반 ChatOps 플랫폼 연구 개발 착수", + "행정기관 SI 사업 10건 수주" + ))); + history.add(Map.of("year", "2020", "events", List.of( + "창립 20주년", + "클라우드 전환 컨설팅 사업 진출" + ))); + history.add(Map.of("year", "2010", "events", List.of( + "ERP·CRM 솔루션 공급 100개사 달성" + ))); + history.add(Map.of("year", "2000", "events", List.of( + "(주)지오정보기술 설립" + ))); + return ResponseEntity.ok(history); + } + + // ── GUARDiA 솔루션 정보 ─────────────────────────────────────── + @GetMapping("/solutions/guardia") + public ResponseEntity> getGuardiaInfo() { + Map g = new LinkedHashMap<>(); + g.put("name", "GUARDiA ITSM"); + g.put("tagline", "AI 기반 레거시 인프라 자율 운영 플랫폼"); + g.put("description", + "1,000개 이상 관공서 레거시 인프라를 대상으로 하는 AI 기반 통합 ChatOps 오케스트레이션 플랫폼. " + + "메신저 한 줄 명령으로 에이전트리스 배포·운영을 자동화합니다."); + g.put("keyFeatures", Arrays.asList( + Map.of("icon", "🤖", "title", "AI 에이전트 자동화", + "desc", "Ollama 온프레미스 sLLM 기반 자연어 명령 → 자동 배포·운영"), + Map.of("icon", "🔧", "title", "에이전트리스 아키텍처", + "desc", "대상 서버에 소프트웨어 설치 없이 SSH/SFTP만으로 관리"), + Map.of("icon", "💬", "title", "ChatOps 메신저 통합", + "desc", "카카오워크·네이버웍스·슬랙 등 메신저에서 직접 인프라 제어"), + Map.of("icon", "📊", "title", "통합 ITSM 대시보드", + "desc", "SR·인시던트·변경관리·SLA·CMDB 전체를 하나의 플랫폼에서"), + Map.of("icon", "🔒", "title", "엔터프라이즈 보안", + "desc", "AES-256-GCM 암호화, MFA, PAM, 불변 감사로그, Zero Trust"), + Map.of("icon", "🏗️", "title", "PMS (프로젝트 관리)", + "desc", "WBS·산출물·일주월 보고서 자동 생성, 이슈·위험 관리") + )); + g.put("editions", Arrays.asList( + Map.of("name", "COMMUNITY", "price", "무료", "target", "소규모 기관", + "features", List.of("기본 SR 관리", "CMDB", "대시보드")), + Map.of("name", "STANDARD", "price", "협의", "target", "중형 기관", + "features", List.of("전체 ITSM", "AI 에이전트", "LDAP/MFA", "SLA")), + Map.of("name", "ENTERPRISE", "price", "협의", "target", "대형 관공서", + "features", List.of("무제한", "취약점 스캔", "Scouter APM", "FinOps", "전담 지원")) + )); + g.put("techStack", Map.of( + "backend", "Python 3.11 / FastAPI", + "ai", "Ollama (온프레미스 sLLM, 외부 API 완전 금지)", + "infra", "paramiko SSH/SFTP (에이전트리스)", + "db", "PostgreSQL / SQLite", + "frontend", "React.js / PWA" + )); + return ResponseEntity.ok(g); + } + + // ── 소식 목록 ──────────────────────────────────────────────── + @GetMapping("/news") + public ResponseEntity> getNews( + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "6") int size, + @RequestParam(required = false) String category) { + Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending()); + return ResponseEntity.ok(newsService.findAll(category, pageable)); + } + + @GetMapping("/news/{id}") + public ResponseEntity getNewsDetail(@PathVariable Long id) { + return newsService.findById(id) + .map(ResponseEntity::ok) + .orElse(ResponseEntity.notFound().build()); + } + + // ── 문의 접수 ──────────────────────────────────────────────── + @PostMapping("/inquiry") + public ResponseEntity> submitInquiry(@Valid @RequestBody Inquiry inquiry) { + inquiryService.save(inquiry); + return ResponseEntity.ok(Map.of( + "message", "문의가 접수되었습니다. 빠른 시일 내에 연락드리겠습니다.", + "status", "SUCCESS" + )); + } + + // ── 채용공고 (공개) ─────────────────────────────────────────── + @GetMapping("/recruits") + public ResponseEntity getRecruits() { + return ResponseEntity.ok(recruitRepo.findByActiveTrueOrderByCreatedAtDesc()); + } + + // ── 메뉴 구조 ──────────────────────────────────────────────── + @GetMapping("/menu") + public ResponseEntity>> getMenu() { + return ResponseEntity.ok(List.of( + Map.of("id", "company", "label", "회사소개", + "children", List.of( + Map.of("id", "greeting", "label", "CEO 인사말", "path", "/company/greeting"), + Map.of("id", "history", "label", "연혁", "path", "/company/history"), + Map.of("id", "organization", "label", "조직도", "path", "/company/organization"), + Map.of("id", "ci", "label", "CI 소개", "path", "/company/ci"), + Map.of("id", "location", "label", "오시는 길", "path", "/company/location") + )), + Map.of("id", "solution", "label", "솔루션", + "children", List.of( + Map.of("id", "guardia", "label", "GUARDiA ITSM", "path", "/solution/guardia", "badge", "NEW"), + Map.of("id", "erp", "label", "ERP", "path", "/solution/erp"), + Map.of("id", "crm", "label", "CRM", "path", "/solution/crm"), + Map.of("id", "bi", "label", "BI", "path", "/solution/bi") + )), + Map.of("id", "business", "label", "사업실적", + "children", List.of( + Map.of("id", "reference", "label", "구축 레퍼런스", "path", "/business/reference"), + Map.of("id", "partner", "label", "파트너", "path", "/business/partner") + )), + Map.of("id", "support", "label", "고객지원", + "children", List.of( + Map.of("id", "notice", "label", "공지사항", "path", "/support/notice"), + Map.of("id", "faq", "label", "FAQ", "path", "/support/faq"), + Map.of("id", "catalog", "label", "카탈로그", "path", "/support/catalog"), + Map.of("id", "contact", "label", "문의하기", "path", "/support/contact") + )), + Map.of("id", "recruit", "label", "채용", + "children", List.of( + Map.of("id", "jobs", "label", "채용공고", "path", "/recruit/jobs"), + Map.of("id", "welfare", "label", "복리후생", "path", "/recruit/welfare"), + Map.of("id", "apply", "label", "지원하기", "path", "/recruit/apply") + )), + Map.of("id", "news", "label", "뉴스", + "children", List.of( + Map.of("id", "newsroom", "label", "뉴스룸", "path", "/news/newsroom"), + Map.of("id", "blog", "label", "기술 블로그", "path", "/news/blog") + )) + )); + } +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/model/AdminUser.java b/backend/src/main/java/kr/co/zioinfo/web/model/AdminUser.java new file mode 100644 index 00000000..14eff8e0 --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/model/AdminUser.java @@ -0,0 +1,32 @@ +package kr.co.zioinfo.web.model; + +import jakarta.persistence.*; +import lombok.*; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import java.time.LocalDateTime; + +@Entity @Table(name = "admin_user") +@Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor +@EntityListeners(AuditingEntityListener.class) +public class AdminUser { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, unique = true, length = 50) + private String username; + + @Column(nullable = false) + private String password; // BCrypt encoded + + @Column(length = 100) + private String displayName; + + @Column(length = 100) + private String email; + + private boolean enabled = true; + + @CreatedDate + private LocalDateTime createdAt; +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/model/Inquiry.java b/backend/src/main/java/kr/co/zioinfo/web/model/Inquiry.java new file mode 100644 index 00000000..7be8f5af --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/model/Inquiry.java @@ -0,0 +1,40 @@ +package kr.co.zioinfo.web.model; + +import jakarta.persistence.*; +import jakarta.validation.constraints.*; +import lombok.*; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import java.time.LocalDateTime; + +@Entity @Table(name = "inquiry") +@Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor +@EntityListeners(AuditingEntityListener.class) +public class Inquiry { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotBlank @Column(nullable = false, length = 50) + private String name; + + @NotBlank @Email @Column(nullable = false, length = 100) + private String email; + + @Column(length = 30) + private String phone; + + @NotBlank @Column(nullable = false, length = 200) + private String subject; + + @NotBlank @Column(nullable = false, columnDefinition = "TEXT") + private String content; + + @Column(length = 50) + private String category; // 제품문의 | 기술지원 | 사업제안 | 기타 + + private boolean agreePrivacy = false; + private String status = "PENDING"; // PENDING | ANSWERED + + @CreatedDate + private LocalDateTime createdAt; +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/model/News.java b/backend/src/main/java/kr/co/zioinfo/web/model/News.java new file mode 100644 index 00000000..99358db5 --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/model/News.java @@ -0,0 +1,36 @@ +package kr.co.zioinfo.web.model; + +import jakarta.persistence.*; +import lombok.*; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import java.time.LocalDateTime; + +@Entity @Table(name = "news") +@Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor +@EntityListeners(AuditingEntityListener.class) +public class News { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 200) + private String title; + + @Column(length = 50) + private String category; // 공지사항 | 보도자료 | 이벤트 + + @Column(columnDefinition = "TEXT") + private String content; + + @Column(length = 500) + private String summary; + + @Column(length = 300) + private String thumbnailUrl; + + private boolean visible = true; + private int viewCount = 0; + + @CreatedDate + private LocalDateTime createdAt; +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/model/Recruit.java b/backend/src/main/java/kr/co/zioinfo/web/model/Recruit.java new file mode 100644 index 00000000..9973fa7d --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/model/Recruit.java @@ -0,0 +1,41 @@ +package kr.co.zioinfo.web.model; + +import jakarta.persistence.*; +import lombok.*; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Entity @Table(name = "recruit") +@Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor +@EntityListeners(AuditingEntityListener.class) +public class Recruit { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 200) + private String title; + + @Column(length = 50) + private String department; // 개발팀, 영업팀, 기획팀 등 + + @Column(length = 20) + private String jobType; // 정규직, 계약직, 인턴 + + @Column(columnDefinition = "TEXT") + private String description; // 담당업무 + + @Column(columnDefinition = "TEXT") + private String requirements; // 지원자격 + + @Column(columnDefinition = "TEXT") + private String preferred; // 우대사항 + + private LocalDate deadline; + private int headcount = 1; + private boolean active = true; + + @CreatedDate + private LocalDateTime createdAt; +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/repository/AdminUserRepository.java b/backend/src/main/java/kr/co/zioinfo/web/repository/AdminUserRepository.java new file mode 100644 index 00000000..8b12d81c --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/repository/AdminUserRepository.java @@ -0,0 +1,10 @@ +package kr.co.zioinfo.web.repository; + +import kr.co.zioinfo.web.model.AdminUser; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + +public interface AdminUserRepository extends JpaRepository { + Optional findByUsername(String username); + boolean existsByUsername(String username); +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/repository/InquiryRepository.java b/backend/src/main/java/kr/co/zioinfo/web/repository/InquiryRepository.java new file mode 100644 index 00000000..6b5f88b0 --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/repository/InquiryRepository.java @@ -0,0 +1,12 @@ +package kr.co.zioinfo.web.repository; + +import kr.co.zioinfo.web.model.Inquiry; +import org.springframework.data.domain.*; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + +public interface InquiryRepository extends JpaRepository { + Page findByStatus(String status, Pageable p); + long countByStatus(String status); + List findTop5ByOrderByCreatedAtDesc(); +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/repository/NewsRepository.java b/backend/src/main/java/kr/co/zioinfo/web/repository/NewsRepository.java new file mode 100644 index 00000000..ce007bc8 --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/repository/NewsRepository.java @@ -0,0 +1,13 @@ +package kr.co.zioinfo.web.repository; + +import kr.co.zioinfo.web.model.News; +import org.springframework.data.domain.*; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + +public interface NewsRepository extends JpaRepository { + Page findByVisibleTrue(Pageable p); + Page findByCategoryAndVisibleTrue(String category, Pageable p); + long countByVisibleTrue(); + List findTop5ByOrderByCreatedAtDesc(); +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/repository/RecruitRepository.java b/backend/src/main/java/kr/co/zioinfo/web/repository/RecruitRepository.java new file mode 100644 index 00000000..65331ad7 --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/repository/RecruitRepository.java @@ -0,0 +1,13 @@ +package kr.co.zioinfo.web.repository; + +import kr.co.zioinfo.web.model.Recruit; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + +public interface RecruitRepository extends JpaRepository { + List findByActiveTrueOrderByCreatedAtDesc(); + Page findAllByOrderByCreatedAtDesc(Pageable pageable); + long countByActiveTrue(); +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/security/JwtAuthFilter.java b/backend/src/main/java/kr/co/zioinfo/web/security/JwtAuthFilter.java new file mode 100644 index 00000000..58e11319 --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/security/JwtAuthFilter.java @@ -0,0 +1,35 @@ +package kr.co.zioinfo.web.security; + +import jakarta.servlet.*; +import jakarta.servlet.http.*; +import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; +import java.io.IOException; +import java.util.List; + +@Component +@RequiredArgsConstructor +public class JwtAuthFilter extends OncePerRequestFilter { + + private final JwtUtil jwtUtil; + + @Override + protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) + throws ServletException, IOException { + String header = req.getHeader("Authorization"); + if (header != null && header.startsWith("Bearer ")) { + String token = header.substring(7); + if (jwtUtil.isValid(token)) { + String username = jwtUtil.extractUsername(token); + var auth = new UsernamePasswordAuthenticationToken( + username, null, List.of(new SimpleGrantedAuthority("ROLE_ADMIN"))); + SecurityContextHolder.getContext().setAuthentication(auth); + } + } + chain.doFilter(req, res); + } +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/security/JwtUtil.java b/backend/src/main/java/kr/co/zioinfo/web/security/JwtUtil.java new file mode 100644 index 00000000..6802336d --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/security/JwtUtil.java @@ -0,0 +1,49 @@ +package kr.co.zioinfo.web.security; + +import io.jsonwebtoken.*; +import io.jsonwebtoken.security.Keys; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import javax.crypto.SecretKey; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +@Component +public class JwtUtil { + + private final SecretKey key; + private final long expirationMs; + + public JwtUtil( + @Value("${zioinfo.jwt.secret:zioinfo-admin-secret-key-must-be-at-least-32-chars}") String secret, + @Value("${zioinfo.jwt.expiration-ms:28800000}") long expirationMs) { + this.key = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8)); + this.expirationMs = expirationMs; + } + + public String generate(String username) { + return Jwts.builder() + .subject(username) + .issuedAt(new Date()) + .expiration(new Date(System.currentTimeMillis() + expirationMs)) + .signWith(key) + .compact(); + } + + public String extractUsername(String token) { + return parse(token).getPayload().getSubject(); + } + + public boolean isValid(String token) { + try { + parse(token); + return true; + } catch (JwtException | IllegalArgumentException e) { + return false; + } + } + + private Jws parse(String token) { + return Jwts.parser().verifyWith(key).build().parseSignedClaims(token); + } +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/service/InquiryService.java b/backend/src/main/java/kr/co/zioinfo/web/service/InquiryService.java new file mode 100644 index 00000000..95f759b8 --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/service/InquiryService.java @@ -0,0 +1,21 @@ +package kr.co.zioinfo.web.service; + +import kr.co.zioinfo.web.model.Inquiry; +import kr.co.zioinfo.web.repository.InquiryRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +@Slf4j +public class InquiryService { + private final InquiryRepository repo; + + public Inquiry save(Inquiry inquiry) { + Inquiry saved = repo.save(inquiry); + log.info("문의 접수: id={} name={} subject={}", saved.getId(), saved.getName(), saved.getSubject()); + // TODO: 이메일 발송 (MailService 연동) + return saved; + } +} diff --git a/backend/src/main/java/kr/co/zioinfo/web/service/NewsService.java b/backend/src/main/java/kr/co/zioinfo/web/service/NewsService.java new file mode 100644 index 00000000..de876d32 --- /dev/null +++ b/backend/src/main/java/kr/co/zioinfo/web/service/NewsService.java @@ -0,0 +1,28 @@ +package kr.co.zioinfo.web.service; + +import kr.co.zioinfo.web.model.News; +import kr.co.zioinfo.web.repository.NewsRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.*; +import org.springframework.stereotype.Service; +import java.util.Optional; + +@Service +@RequiredArgsConstructor +public class NewsService { + private final NewsRepository repo; + + public Page findAll(String category, Pageable pageable) { + if (category != null && !category.isBlank()) { + return repo.findByCategoryAndVisibleTrue(category, pageable); + } + return repo.findByVisibleTrue(pageable); + } + + public Optional findById(Long id) { + return repo.findById(id).map(n -> { + n.setViewCount(n.getViewCount() + 1); + return repo.save(n); + }); + } +} diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml new file mode 100644 index 00000000..40e7a4cf --- /dev/null +++ b/backend/src/main/resources/application.yml @@ -0,0 +1,52 @@ +server: + port: 8080 + servlet: + encoding: + charset: UTF-8 + force: true + +spring: + application: + name: zioinfo-web + datasource: + # SQLite — 파일 기반 DB (data/ 디렉토리 자동 생성) + url: jdbc:sqlite:./data/zioinfo.db + driver-class-name: org.sqlite.JDBC + jpa: + database-platform: org.hibernate.community.dialect.SQLiteDialect + hibernate: + ddl-auto: update # 스키마 자동 갱신 (운영: validate) + show-sql: false + properties: + hibernate: + format_sql: true + # SQLite는 foreign key 비활성 기본 → 명시 활성화 + javax.persistence.schema-generation.database.action: none + mail: + host: ${MAIL_HOST:smtp.gmail.com} + port: ${MAIL_PORT:587} + username: ${MAIL_USERNAME:} + password: ${MAIL_PASSWORD:} + properties: + mail.smtp.auth: true + mail.smtp.starttls.enable: true + +zioinfo: + jwt: + secret: zioinfo-admin-jwt-secret-key-must-be-at-least-32-chars-long + expiration-ms: 28800000 # 8시간 + company: + name: (주)지오정보기술 + email: info@zioinfo.co.kr + phone: 02-000-0000 + address: 서울특별시 + cors: + allowed-origins: + - http://localhost:3000 + - http://localhost:5173 + - http://www.zioinfo.co.kr + +logging: + level: + kr.co.zioinfo: DEBUG + org.hibernate.SQL: WARN diff --git a/backend/src/main/resources/static/assets/AdminDashboard-B5ryl_KI.js b/backend/src/main/resources/static/assets/AdminDashboard-B5ryl_KI.js new file mode 100644 index 00000000..ee3f847e --- /dev/null +++ b/backend/src/main/resources/static/assets/AdminDashboard-B5ryl_KI.js @@ -0,0 +1 @@ +import{r as a,j as e,L as n}from"./index-ChpGil2q.js";const h=s=>fetch(s,{headers:{Authorization:`Bearer ${localStorage.getItem("admin_token")}`}}).then(l=>l.json());function x(){var t,r;const[s,l]=a.useState(null),[c,d]=a.useState(!0);if(a.useEffect(()=>{h("/api/admin/dashboard").then(l).finally(()=>d(!1))},[]),c)return e.jsx("p",{style:{color:"#64748b",fontSize:14},children:"로딩 중..."});if(!s)return null;const o=[{icon:"📰",label:"전체 뉴스",value:s.totalNews,sub:`공개 ${s.visibleNews}건`,color:"blue"},{icon:"📩",label:"전체 문의",value:s.totalInquiries,sub:`미답변 ${s.pendingInquiries}건`,color:s.pendingInquiries>0?"red":"green"},{icon:"👥",label:"채용공고",value:s.totalRecruits,sub:`진행중 ${s.activeRecruits}건`,color:"green"}];return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"admin-stats",children:[o.map(i=>e.jsxs("div",{className:"stat-card",children:[e.jsx("div",{className:`stat-icon ${i.color}`,children:i.icon}),e.jsxs("div",{className:"stat-info",children:[e.jsx("h4",{children:i.value}),e.jsxs("p",{children:[i.label,e.jsx("br",{}),e.jsx("span",{style:{fontSize:11},children:i.sub})]})]})]},i.label)),s.pendingInquiries>0&&e.jsxs("div",{className:"stat-card",style:{borderLeft:"3px solid #ef4444"},children:[e.jsx("div",{className:"stat-icon red",children:"🔔"}),e.jsxs("div",{className:"stat-info",children:[e.jsx("h4",{style:{color:"#ef4444"},children:s.pendingInquiries}),e.jsxs("p",{children:["미답변 문의",e.jsx("br",{}),e.jsx(n,{to:"/admin/inquiries",style:{fontSize:11,color:"#ef4444"},children:"바로가기 →"})]})]})]})]}),e.jsxs("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:16},children:[e.jsxs("div",{className:"admin-card",children:[e.jsxs("div",{className:"admin-card-header",children:[e.jsx("h3",{children:"📰 최근 뉴스"}),e.jsx(n,{to:"/admin/news",className:"btn btn-outline btn-sm",children:"전체보기"})]}),e.jsxs("ul",{className:"recent-list",children:[(s.recentNews||[]).map(i=>e.jsxs("li",{children:[e.jsx("span",{className:"rl-dot"}),e.jsx("span",{className:"rl-title",children:i.title}),e.jsx("span",{className:"rl-meta",children:i.category})]},i.id)),!((t=s.recentNews)!=null&&t.length)&&e.jsx("li",{style:{color:"#94a3b8",fontSize:13},children:"등록된 뉴스가 없습니다."})]})]}),e.jsxs("div",{className:"admin-card",children:[e.jsxs("div",{className:"admin-card-header",children:[e.jsx("h3",{children:"📩 최근 문의"}),e.jsx(n,{to:"/admin/inquiries",className:"btn btn-outline btn-sm",children:"전체보기"})]}),e.jsxs("ul",{className:"recent-list",children:[(s.recentInquiries||[]).map(i=>e.jsxs("li",{children:[e.jsx("span",{className:"rl-dot",style:{background:i.status==="PENDING"?"#ef4444":"#22c55e"}}),e.jsx("span",{className:"rl-title",children:i.subject}),e.jsx("span",{className:"rl-meta",children:i.name})]},i.id)),!((r=s.recentInquiries)!=null&&r.length)&&e.jsx("li",{style:{color:"#94a3b8",fontSize:13},children:"접수된 문의가 없습니다."})]})]})]})]})}export{x as default}; diff --git a/backend/src/main/resources/static/assets/AdminInquiry-BBFBdE8S.js b/backend/src/main/resources/static/assets/AdminInquiry-BBFBdE8S.js new file mode 100644 index 00000000..448067bd --- /dev/null +++ b/backend/src/main/resources/static/assets/AdminInquiry-BBFBdE8S.js @@ -0,0 +1 @@ +import{r as c,j as e}from"./index-ChpGil2q.js";const E=()=>localStorage.getItem("admin_token"),j=(a,l={})=>fetch(a,{...l,headers:{"Content-Type":"application/json",Authorization:`Bearer ${E()}`,...l.headers}}),b={PENDING:"미답변",ANSWERED:"답변완료",CLOSED:"종결"},g={PENDING:"badge-red",ANSWERED:"badge-green",CLOSED:"badge-gray"};function D(){var p;const[a,l]=c.useState(0),[o,N]=c.useState(""),[i,f]=c.useState({content:[],totalPages:0,totalElements:0}),[n,d]=c.useState(null),[h,u]=c.useState(null),S=(s,t="success")=>{u({msg:s,type:t}),setTimeout(()=>u(null),2500)},m=c.useCallback(()=>{const s=o?`&status=${o}`:"";j(`/api/admin/inquiries?page=${a}&size=10${s}`).then(t=>t.json()).then(f)},[a,o]);c.useEffect(()=>{m()},[m]);const r=async(s,t)=>{(await j(`/api/admin/inquiries/${s}/status`,{method:"PATCH",body:JSON.stringify({status:t})})).ok&&(m(),(n==null?void 0:n.id)===s&&d(v=>({...v,status:t})),S("상태가 변경되었습니다."))},y=async s=>{const t=await j(`/api/admin/inquiries/${s}`);t.ok&&d(await t.json())};return e.jsxs(e.Fragment,{children:[h&&e.jsx("div",{className:"admin-toast",children:e.jsx("div",{className:`toast-item ${h.type}`,children:h.msg})}),e.jsxs("div",{className:"admin-card",children:[e.jsxs("div",{className:"admin-toolbar",children:[e.jsxs("span",{style:{fontSize:13,color:"#64748b"},children:["전체 ",i.totalElements,"건"]}),e.jsxs("select",{className:"admin-select",value:o,onChange:s=>{N(s.target.value),l(0)},children:[e.jsx("option",{value:"",children:"전체 상태"}),e.jsx("option",{value:"PENDING",children:"미답변"}),e.jsx("option",{value:"ANSWERED",children:"답변완료"}),e.jsx("option",{value:"CLOSED",children:"종결"})]})]}),e.jsx("div",{className:"admin-table-wrap",children:e.jsxs("table",{className:"admin-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"No"}),e.jsx("th",{children:"이름"}),e.jsx("th",{children:"제목"}),e.jsx("th",{children:"카테고리"}),e.jsx("th",{children:"상태"}),e.jsx("th",{children:"접수일"}),e.jsx("th",{children:"관리"})]})}),e.jsxs("tbody",{children:[i.content.map((s,t)=>{var x;return e.jsxs("tr",{style:{cursor:"pointer"},children:[e.jsx("td",{style:{color:"#94a3b8",fontSize:12},children:i.totalElements-a*10-t}),e.jsx("td",{children:s.name}),e.jsx("td",{onClick:()=>y(s.id),children:e.jsx("span",{className:"truncate",style:{display:"block",color:"#4f6ef7",cursor:"pointer"},children:s.subject})}),e.jsx("td",{children:e.jsx("span",{className:"badge badge-blue",children:s.category||"기타"})}),e.jsx("td",{children:e.jsx("span",{className:`badge ${g[s.status]||"badge-gray"}`,children:b[s.status]||s.status})}),e.jsx("td",{style:{fontSize:12,color:"#94a3b8"},children:(x=s.createdAt)==null?void 0:x.slice(0,10)}),e.jsx("td",{children:e.jsxs("div",{className:"action-btns",children:[s.status==="PENDING"&&e.jsx("button",{className:"btn btn-outline btn-sm",onClick:()=>r(s.id,"ANSWERED"),children:"답변완료"}),s.status!=="CLOSED"&&e.jsx("button",{className:"btn btn-outline btn-sm",onClick:()=>r(s.id,"CLOSED"),children:"종결"})]})})]},s.id)}),!i.content.length&&e.jsx("tr",{children:e.jsx("td",{colSpan:7,children:e.jsxs("div",{className:"empty-state",children:[e.jsx("div",{className:"empty-icon",children:"📩"}),e.jsx("p",{children:"접수된 문의가 없습니다."})]})})})]})]})}),i.totalPages>1&&e.jsxs("div",{className:"admin-pagination",children:[e.jsxs("span",{className:"admin-pagination-info",children:["페이지 ",a+1," / ",i.totalPages]}),e.jsxs("div",{className:"pagination-btns",children:[e.jsx("button",{disabled:a===0,onClick:()=>l(s=>s-1),children:"‹"}),Array.from({length:Math.min(i.totalPages,7)},(s,t)=>e.jsx("button",{className:a===t?"active":"",onClick:()=>l(t),children:t+1},t)),e.jsx("button",{disabled:a>=i.totalPages-1,onClick:()=>l(s=>s+1),children:"›"})]})]})]}),n&&e.jsx("div",{className:"modal-backdrop",onClick:s=>s.target===s.currentTarget&&d(null),children:e.jsxs("div",{className:"modal",children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:"문의 상세"}),e.jsx("button",{onClick:()=>d(null),children:"✕"})]}),e.jsxs("div",{className:"modal-body",children:[e.jsx("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:12,marginBottom:16},children:[["이름",n.name],["이메일",n.email],["연락처",n.phone||"-"],["유형",n.category||"기타"]].map(([s,t])=>e.jsxs("div",{children:[e.jsx("div",{style:{fontSize:11,fontWeight:600,color:"#64748b",marginBottom:3,textTransform:"uppercase"},children:s}),e.jsx("div",{style:{fontSize:13.5},children:t})]},s))}),e.jsxs("div",{style:{marginBottom:12},children:[e.jsx("div",{style:{fontSize:11,fontWeight:600,color:"#64748b",marginBottom:4,textTransform:"uppercase"},children:"제목"}),e.jsx("div",{style:{fontWeight:600,fontSize:15},children:n.subject})]}),e.jsxs("div",{children:[e.jsx("div",{style:{fontSize:11,fontWeight:600,color:"#64748b",marginBottom:6,textTransform:"uppercase"},children:"내용"}),e.jsx("div",{style:{background:"#f8fafc",borderRadius:8,padding:"14px 16px",fontSize:13.5,lineHeight:1.7,whiteSpace:"pre-wrap",border:"1px solid #e2e8f0"},children:n.content})]}),e.jsxs("div",{style:{marginTop:16,display:"flex",alignItems:"center",gap:8},children:[e.jsxs("span",{style:{fontSize:12,color:"#64748b"},children:["접수일: ",(p=n.createdAt)==null?void 0:p.slice(0,16)]}),e.jsx("span",{className:`badge ${g[n.status]||"badge-gray"}`,children:b[n.status]})]})]}),e.jsxs("div",{className:"modal-footer",children:[n.status==="PENDING"&&e.jsx("button",{className:"btn btn-primary",onClick:()=>r(n.id,"ANSWERED"),children:"답변완료 처리"}),n.status!=="CLOSED"&&e.jsx("button",{className:"btn btn-outline",onClick:()=>r(n.id,"CLOSED"),children:"종결"}),e.jsx("button",{className:"btn btn-outline",onClick:()=>d(null),children:"닫기"})]})]})})]})}export{D as default}; diff --git a/backend/src/main/resources/static/assets/AdminLayout-uWX9KsdF.js b/backend/src/main/resources/static/assets/AdminLayout-uWX9KsdF.js new file mode 100644 index 00000000..24199364 --- /dev/null +++ b/backend/src/main/resources/static/assets/AdminLayout-uWX9KsdF.js @@ -0,0 +1 @@ +import{c as g,u as x,r as s,j as a,N as b,O as j}from"./index-ChpGil2q.js";/* empty css */const N=[{section:"메인"},{path:"/admin/dashboard",icon:"📊",label:"대시보드"},{section:"콘텐츠 관리"},{path:"/admin/news",icon:"📰",label:"뉴스/공지사항"},{path:"/admin/recruit",icon:"👥",label:"채용공고"},{section:"고객 관리"},{path:"/admin/inquiries",icon:"📩",label:"문의 관리",badgeKey:"pendingInquiries"},{section:"시스템"},{path:"/admin/settings",icon:"⚙️",label:"설정"}];function y(){const i=g(),d=x(),[t,r]=s.useState(null),[l,m]=s.useState("대시보드"),[o,h]=s.useState({});s.useEffect(()=>{const e=localStorage.getItem("admin_token");if(!e){i("/admin/login");return}const n=JSON.parse(localStorage.getItem("admin_user")||"{}");r(n),u(e)},[i]),s.useEffect(()=>{m({"/admin/dashboard":"대시보드","/admin/news":"뉴스/공지사항 관리","/admin/inquiries":"문의 관리","/admin/recruit":"채용공고 관리","/admin/settings":"설정"}[d.pathname]||"관리자")},[d.pathname]);const u=async e=>{try{const n=await fetch("/api/admin/dashboard",{headers:{Authorization:`Bearer ${e}`}});if(n.ok){const c=await n.json();h({pendingInquiries:c.pendingInquiries||0})}}catch{}},p=()=>{localStorage.removeItem("admin_token"),localStorage.removeItem("admin_user"),i("/admin/login")};return t?a.jsxs("div",{className:"admin-wrap",children:[a.jsxs("aside",{className:"admin-sidebar",children:[a.jsxs("div",{className:"admin-sidebar-logo",children:[a.jsx("h2",{children:"ZioInfo Admin"}),a.jsx("span",{children:"(주)지오정보기술 관리자"})]}),a.jsx("nav",{className:"admin-nav",children:N.map((e,n)=>e.section?a.jsx("div",{className:"admin-nav-section",children:e.section},n):a.jsxs(b,{to:e.path,className:({isActive:c})=>c?"active":"",children:[a.jsx("span",{className:"nav-icon",children:e.icon}),e.label,e.badgeKey&&o[e.badgeKey]>0&&a.jsx("span",{className:"admin-nav-badge",children:o[e.badgeKey]})]},e.path))}),a.jsx("div",{className:"admin-sidebar-footer",children:a.jsx("button",{onClick:p,children:"🚪 로그아웃"})})]}),a.jsxs("main",{className:"admin-main",children:[a.jsxs("div",{className:"admin-topbar",children:[a.jsx("h1",{children:l}),a.jsxs("div",{className:"admin-topbar-right",children:[a.jsxs("span",{className:"admin-user-badge",children:["👤 ",t.displayName||t.username]}),a.jsx("a",{href:"/",target:"_blank",rel:"noreferrer",style:{fontSize:12,color:"#64748b",textDecoration:"none"},children:"🌐 홈페이지 보기"})]})]}),a.jsx("div",{className:"admin-content",children:a.jsx(j,{})})]})]}):null}export{y as default}; diff --git a/backend/src/main/resources/static/assets/AdminLogin-DcRT5LbX.js b/backend/src/main/resources/static/assets/AdminLogin-DcRT5LbX.js new file mode 100644 index 00000000..d426fba0 --- /dev/null +++ b/backend/src/main/resources/static/assets/AdminLogin-DcRT5LbX.js @@ -0,0 +1 @@ +import{r as i,c as p,j as e}from"./index-ChpGil2q.js";/* empty css */function x(){const[t,o]=i.useState({username:"",password:""}),[l,r]=i.useState(""),[d,c]=i.useState(!1),m=p(),u=async a=>{a.preventDefault(),r(""),c(!0);try{const s=await fetch("/api/admin/login",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),n=await s.json();if(!s.ok){r(n.message||"로그인 실패");return}localStorage.setItem("admin_token",n.token),localStorage.setItem("admin_user",JSON.stringify({username:n.username,displayName:n.displayName})),m("/admin/dashboard")}catch{r("서버 연결 오류가 발생했습니다.")}finally{c(!1)}};return e.jsx("div",{className:"admin-login-page",children:e.jsxs("div",{className:"admin-login-box",children:[e.jsxs("div",{className:"login-logo",children:[e.jsx("span",{className:"login-badge",children:"ADMIN"}),e.jsx("h1",{children:"(주)지오정보기술"}),e.jsx("p",{children:"홈페이지 관리자 시스템"})]}),l&&e.jsxs("div",{className:"login-error",children:["⚠ ",l]}),e.jsxs("form",{onSubmit:u,children:[e.jsxs("div",{className:"login-input-group",children:[e.jsx("label",{children:"아이디"}),e.jsx("input",{type:"text",placeholder:"관리자 아이디",value:t.username,required:!0,onChange:a=>o(s=>({...s,username:a.target.value}))})]}),e.jsxs("div",{className:"login-input-group",children:[e.jsx("label",{children:"비밀번호"}),e.jsx("input",{type:"password",placeholder:"비밀번호",value:t.password,required:!0,onChange:a=>o(s=>({...s,password:a.target.value}))})]}),e.jsx("button",{type:"submit",className:"login-btn",disabled:d,children:d?"로그인 중...":"로그인"})]}),e.jsxs("p",{style:{textAlign:"center",marginTop:20,fontSize:12,color:"#94a3b8"},children:["홈페이지로 돌아가기: ",e.jsx("a",{href:"/",style:{color:"#4f6ef7"},children:"메인 페이지"})]})]})})}export{x as default}; diff --git a/backend/src/main/resources/static/assets/AdminNews-CDSgPR9E.js b/backend/src/main/resources/static/assets/AdminNews-CDSgPR9E.js new file mode 100644 index 00000000..fb4a04da --- /dev/null +++ b/backend/src/main/resources/static/assets/AdminNews-CDSgPR9E.js @@ -0,0 +1 @@ +import{r as l,j as e}from"./index-ChpGil2q.js";const P=()=>localStorage.getItem("admin_token"),x=(a,c={})=>fetch(a,{...c,headers:{"Content-Type":"application/json",Authorization:`Bearer ${P()}`,...c.headers}}),f={title:"",category:"공지사항",summary:"",content:"",thumbnailUrl:"",visible:!0},$=["공지사항","보도자료","이벤트"];function z(){const[a,c]=l.useState(0),[n,y]=l.useState({content:[],totalPages:0,totalElements:0}),[C,o]=l.useState(null),[i,j]=l.useState(f),[r,g]=l.useState(null),[p,v]=l.useState(!1),[u,N]=l.useState(null),b=(s,t="success")=>{N({msg:s,type:t}),setTimeout(()=>N(null),2500)},m=l.useCallback(()=>{x(`/api/admin/news?page=${a}&size=10`).then(s=>s.json()).then(y)},[a]);l.useEffect(()=>{m()},[m]);const k=()=>{j(f),g(null),o("form")},S=s=>{j({...s}),g(s.id),o("form")},w=async()=>{v(!0);const s=r?`/api/admin/news/${r}`:"/api/admin/news",h=await x(s,{method:r?"PUT":"POST",body:JSON.stringify(i)});v(!1),h.ok?(o(null),m(),b(r?"수정되었습니다.":"등록되었습니다.")):b("저장 실패","error")},E=async s=>{if(!confirm("삭제하시겠습니까?"))return;(await x(`/api/admin/news/${s}`,{method:"DELETE"})).ok&&(m(),b("삭제되었습니다."))},T=async s=>{await x(`/api/admin/news/${s}/visibility`,{method:"PATCH"}),m()},d=(s,t)=>j(h=>({...h,[s]:t}));return e.jsxs(e.Fragment,{children:[u&&e.jsx("div",{className:"admin-toast",children:e.jsx("div",{className:`toast-item ${u.type}`,children:u.msg})}),e.jsxs("div",{className:"admin-card",children:[e.jsxs("div",{className:"admin-toolbar",children:[e.jsxs("span",{style:{fontSize:13,color:"#64748b"},children:["전체 ",n.totalElements,"건"]}),e.jsx("div",{className:"admin-toolbar-right",children:e.jsx("button",{className:"btn btn-primary",onClick:k,children:"+ 뉴스 등록"})})]}),e.jsx("div",{className:"admin-table-wrap",children:e.jsxs("table",{className:"admin-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"No"}),e.jsx("th",{children:"제목"}),e.jsx("th",{children:"카테고리"}),e.jsx("th",{children:"공개"}),e.jsx("th",{children:"조회수"}),e.jsx("th",{children:"등록일"}),e.jsx("th",{children:"관리"})]})}),e.jsxs("tbody",{children:[n.content.map((s,t)=>{var h;return e.jsxs("tr",{children:[e.jsx("td",{style:{color:"#94a3b8",fontSize:12},children:n.totalElements-a*10-t}),e.jsx("td",{children:e.jsx("span",{className:"truncate",style:{display:"block"},children:s.title})}),e.jsx("td",{children:e.jsx("span",{className:`badge ${s.category==="보도자료"?"badge-blue":s.category==="이벤트"?"badge-orange":"badge-gray"}`,children:s.category})}),e.jsx("td",{children:e.jsx("button",{onClick:()=>T(s.id),className:`badge ${s.visible?"badge-green":"badge-red"}`,style:{cursor:"pointer",border:"none"},children:s.visible?"공개":"비공개"})}),e.jsx("td",{children:s.viewCount}),e.jsx("td",{style:{fontSize:12,color:"#94a3b8"},children:(h=s.createdAt)==null?void 0:h.slice(0,10)}),e.jsx("td",{children:e.jsxs("div",{className:"action-btns",children:[e.jsx("button",{className:"btn btn-outline btn-sm",onClick:()=>S(s),children:"수정"}),e.jsx("button",{className:"btn btn-danger btn-sm",onClick:()=>E(s.id),children:"삭제"})]})})]},s.id)}),!n.content.length&&e.jsx("tr",{children:e.jsx("td",{colSpan:7,children:e.jsxs("div",{className:"empty-state",children:[e.jsx("div",{className:"empty-icon",children:"📰"}),e.jsx("p",{children:"등록된 뉴스가 없습니다."})]})})})]})]})}),n.totalPages>1&&e.jsxs("div",{className:"admin-pagination",children:[e.jsxs("span",{className:"admin-pagination-info",children:["페이지 ",a+1," / ",n.totalPages]}),e.jsxs("div",{className:"pagination-btns",children:[e.jsx("button",{disabled:a===0,onClick:()=>c(s=>s-1),children:"‹"}),Array.from({length:n.totalPages},(s,t)=>e.jsx("button",{className:a===t?"active":"",onClick:()=>c(t),children:t+1},t)),e.jsx("button",{disabled:a>=n.totalPages-1,onClick:()=>c(s=>s+1),children:"›"})]})]})]}),C==="form"&&e.jsx("div",{className:"modal-backdrop",onClick:s=>s.target===s.currentTarget&&o(null),children:e.jsxs("div",{className:"modal",children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:r?"뉴스 수정":"뉴스 등록"}),e.jsx("button",{onClick:()=>o(null),children:"✕"})]}),e.jsxs("div",{className:"modal-body",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"제목 *"}),e.jsx("input",{className:"form-control",value:i.title,onChange:s=>d("title",s.target.value),placeholder:"뉴스 제목을 입력하세요"})]}),e.jsxs("div",{className:"form-row",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"카테고리"}),e.jsx("select",{className:"form-control",value:i.category,onChange:s=>d("category",s.target.value),children:$.map(s=>e.jsx("option",{children:s},s))})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"공개 여부"}),e.jsxs("select",{className:"form-control",value:i.visible,onChange:s=>d("visible",s.target.value==="true"),children:[e.jsx("option",{value:"true",children:"공개"}),e.jsx("option",{value:"false",children:"비공개"})]})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"요약"}),e.jsx("input",{className:"form-control",value:i.summary||"",onChange:s=>d("summary",s.target.value),placeholder:"목록에 표시될 요약 문구"})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"썸네일 URL"}),e.jsx("input",{className:"form-control",value:i.thumbnailUrl||"",onChange:s=>d("thumbnailUrl",s.target.value),placeholder:"https://..."})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"본문 내용 *"}),e.jsx("textarea",{className:"form-control",rows:8,value:i.content||"",onChange:s=>d("content",s.target.value),placeholder:"뉴스 본문 내용을 입력하세요"})]})]}),e.jsxs("div",{className:"modal-footer",children:[e.jsx("button",{className:"btn btn-outline",onClick:()=>o(null),children:"취소"}),e.jsx("button",{className:"btn btn-primary",onClick:w,disabled:p||!i.title,children:p?"저장 중...":r?"수정 완료":"등록"})]})]})})]})}export{z as default}; diff --git a/backend/src/main/resources/static/assets/AdminRecruit-CfX4mhQb.js b/backend/src/main/resources/static/assets/AdminRecruit-CfX4mhQb.js new file mode 100644 index 00000000..81593332 --- /dev/null +++ b/backend/src/main/resources/static/assets/AdminRecruit-CfX4mhQb.js @@ -0,0 +1 @@ +import{r,j as e}from"./index-ChpGil2q.js";const P=()=>localStorage.getItem("admin_token"),u=(l,c={})=>fetch(l,{...c,headers:{"Content-Type":"application/json",Authorization:`Bearer ${P()}`,...c.headers}}),f={title:"",department:"",jobType:"정규직",description:"",requirements:"",preferred:"",deadline:"",headcount:1,active:!0},w=["정규직","계약직","인턴","프리랜서"];function z(){const[l,c]=r.useState(0),[i,N]=r.useState({content:[],totalPages:0,totalElements:0}),[y,d]=r.useState(!1),[t,m]=r.useState(f),[o,p]=r.useState(null),[b,g]=r.useState(!1),[j,v]=r.useState(null),x=(s,a="success")=>{v({msg:s,type:a}),setTimeout(()=>v(null),2500)},h=r.useCallback(()=>{u(`/api/admin/recruits?page=${l}&size=10`).then(s=>s.json()).then(N)},[l]);r.useEffect(()=>{h()},[h]);const C=()=>{m(f),p(null),d(!0)},S=s=>{m({...s,deadline:s.deadline||""}),p(s.id),d(!0)},k=async()=>{g(!0);const s=o?`/api/admin/recruits/${o}`:"/api/admin/recruits",a=await u(s,{method:o?"PUT":"POST",body:JSON.stringify(t)});g(!1),a.ok?(d(!1),h(),x(o?"수정되었습니다.":"등록되었습니다.")):x("저장 실패","error")},T=async s=>{if(!confirm("삭제하시겠습니까?"))return;(await u(`/api/admin/recruits/${s}`,{method:"DELETE"})).ok&&(h(),x("삭제되었습니다."))},n=(s,a)=>m(E=>({...E,[s]:a}));return e.jsxs(e.Fragment,{children:[j&&e.jsx("div",{className:"admin-toast",children:e.jsx("div",{className:`toast-item ${j.type}`,children:j.msg})}),e.jsxs("div",{className:"admin-card",children:[e.jsxs("div",{className:"admin-toolbar",children:[e.jsxs("span",{style:{fontSize:13,color:"#64748b"},children:["전체 ",i.totalElements,"건"]}),e.jsx("div",{className:"admin-toolbar-right",children:e.jsx("button",{className:"btn btn-primary",onClick:C,children:"+ 채용공고 등록"})})]}),e.jsx("div",{className:"admin-table-wrap",children:e.jsxs("table",{className:"admin-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"No"}),e.jsx("th",{children:"공고명"}),e.jsx("th",{children:"부서"}),e.jsx("th",{children:"유형"}),e.jsx("th",{children:"모집인원"}),e.jsx("th",{children:"마감일"}),e.jsx("th",{children:"상태"}),e.jsx("th",{children:"관리"})]})}),e.jsxs("tbody",{children:[i.content.map((s,a)=>e.jsxs("tr",{children:[e.jsx("td",{style:{color:"#94a3b8",fontSize:12},children:i.totalElements-l*10-a}),e.jsx("td",{children:e.jsx("span",{className:"truncate",style:{display:"block"},children:s.title})}),e.jsx("td",{children:s.department||"-"}),e.jsx("td",{children:e.jsx("span",{className:`badge ${s.jobType==="정규직"?"badge-blue":s.jobType==="인턴"?"badge-orange":"badge-gray"}`,children:s.jobType})}),e.jsxs("td",{children:[s.headcount,"명"]}),e.jsx("td",{style:{fontSize:12},children:s.deadline||"상시"}),e.jsx("td",{children:e.jsx("span",{className:`badge ${s.active?"badge-green":"badge-red"}`,children:s.active?"진행중":"마감"})}),e.jsx("td",{children:e.jsxs("div",{className:"action-btns",children:[e.jsx("button",{className:"btn btn-outline btn-sm",onClick:()=>S(s),children:"수정"}),e.jsx("button",{className:"btn btn-danger btn-sm",onClick:()=>T(s.id),children:"삭제"})]})})]},s.id)),!i.content.length&&e.jsx("tr",{children:e.jsx("td",{colSpan:8,children:e.jsxs("div",{className:"empty-state",children:[e.jsx("div",{className:"empty-icon",children:"👥"}),e.jsx("p",{children:"등록된 채용공고가 없습니다."})]})})})]})]})}),i.totalPages>1&&e.jsxs("div",{className:"admin-pagination",children:[e.jsxs("span",{className:"admin-pagination-info",children:["페이지 ",l+1," / ",i.totalPages]}),e.jsxs("div",{className:"pagination-btns",children:[e.jsx("button",{disabled:l===0,onClick:()=>c(s=>s-1),children:"‹"}),Array.from({length:i.totalPages},(s,a)=>e.jsx("button",{className:l===a?"active":"",onClick:()=>c(a),children:a+1},a)),e.jsx("button",{disabled:l>=i.totalPages-1,onClick:()=>c(s=>s+1),children:"›"})]})]})]}),y&&e.jsx("div",{className:"modal-backdrop",onClick:s=>s.target===s.currentTarget&&d(!1),children:e.jsxs("div",{className:"modal",children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:o?"채용공고 수정":"채용공고 등록"}),e.jsx("button",{onClick:()=>d(!1),children:"✕"})]}),e.jsxs("div",{className:"modal-body",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"공고 제목 *"}),e.jsx("input",{className:"form-control",value:t.title,onChange:s=>n("title",s.target.value),placeholder:"예: 백엔드 개발자 (Java/Spring)"})]}),e.jsxs("div",{className:"form-row",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"부서"}),e.jsx("input",{className:"form-control",value:t.department,onChange:s=>n("department",s.target.value),placeholder:"개발팀, 영업팀 등"})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"고용형태"}),e.jsx("select",{className:"form-control",value:t.jobType,onChange:s=>n("jobType",s.target.value),children:w.map(s=>e.jsx("option",{children:s},s))})]})]}),e.jsxs("div",{className:"form-row",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"모집 인원"}),e.jsx("input",{type:"number",min:1,className:"form-control",value:t.headcount,onChange:s=>n("headcount",parseInt(s.target.value))})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"마감일"}),e.jsx("input",{type:"date",className:"form-control",value:t.deadline,onChange:s=>n("deadline",s.target.value)})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"공고 상태"}),e.jsxs("select",{className:"form-control",value:t.active,onChange:s=>n("active",s.target.value==="true"),children:[e.jsx("option",{value:"true",children:"진행중"}),e.jsx("option",{value:"false",children:"마감"})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"담당 업무"}),e.jsx("textarea",{className:"form-control",rows:4,value:t.description,onChange:s=>n("description",s.target.value),placeholder:"- 주요 담당 업무를 입력하세요"})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"지원 자격"}),e.jsx("textarea",{className:"form-control",rows:4,value:t.requirements,onChange:s=>n("requirements",s.target.value),placeholder:"- 필수 자격요건을 입력하세요"})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"우대 사항"}),e.jsx("textarea",{className:"form-control",rows:3,value:t.preferred,onChange:s=>n("preferred",s.target.value),placeholder:"- 우대 사항을 입력하세요"})]})]}),e.jsxs("div",{className:"modal-footer",children:[e.jsx("button",{className:"btn btn-outline",onClick:()=>d(!1),children:"취소"}),e.jsx("button",{className:"btn btn-primary",onClick:k,disabled:b||!t.title,children:b?"저장 중...":o?"수정 완료":"등록"})]})]})})]})}export{z as default}; diff --git a/backend/src/main/resources/static/assets/AdminSettings-DaHEGHsg.js b/backend/src/main/resources/static/assets/AdminSettings-DaHEGHsg.js new file mode 100644 index 00000000..7465e66b --- /dev/null +++ b/backend/src/main/resources/static/assets/AdminSettings-DaHEGHsg.js @@ -0,0 +1 @@ +import{c as u,r as d,j as e}from"./index-ChpGil2q.js";const h=()=>localStorage.getItem("admin_token");function f(){const m=u(),i=JSON.parse(localStorage.getItem("admin_user")||"{}"),[r,n]=d.useState({currentPassword:"",newPassword:"",confirmPassword:""}),[t,o]=d.useState(null),[l,c]=d.useState(!1),p=async()=>{if(r.newPassword!==r.confirmPassword){o({text:"새 비밀번호가 일치하지 않습니다.",type:"error"});return}if(r.newPassword.length<8){o({text:"비밀번호는 8자 이상이어야 합니다.",type:"error"});return}c(!0);const s=await fetch("/api/admin/password",{method:"PUT",headers:{"Content-Type":"application/json",Authorization:`Bearer ${h()}`},body:JSON.stringify({currentPassword:r.currentPassword,newPassword:r.newPassword})}),a=await s.json();c(!1),s.ok?(o({text:"비밀번호가 변경되었습니다. 다시 로그인해주세요.",type:"success"}),n({currentPassword:"",newPassword:"",confirmPassword:""}),setTimeout(()=>{localStorage.removeItem("admin_token"),m("/admin/login")},2e3)):o({text:a.message||"변경 실패",type:"error"})};return e.jsxs("div",{style:{maxWidth:520},children:[e.jsxs("div",{className:"admin-card",style:{marginBottom:20},children:[e.jsx("div",{className:"admin-card-header",children:e.jsx("h3",{children:"👤 계정 정보"})}),e.jsx("div",{style:{display:"grid",gap:12},children:[["아이디",i.username],["표시 이름",i.displayName||"-"]].map(([s,a])=>e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12},children:[e.jsx("span",{style:{fontSize:12,fontWeight:600,color:"#64748b",width:80},children:s}),e.jsx("span",{style:{fontSize:14},children:a})]},s))})]}),e.jsxs("div",{className:"admin-card",children:[e.jsx("div",{className:"admin-card-header",children:e.jsx("h3",{children:"🔒 비밀번호 변경"})}),t&&e.jsx("div",{style:{padding:"10px 14px",borderRadius:7,marginBottom:16,fontSize:13,background:t.type==="error"?"#fff1f2":"#f0fdf4",color:t.type==="error"?"#dc2626":"#16a34a",border:`1px solid ${t.type==="error"?"#fecaca":"#bbf7d0"}`},children:t.text}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"현재 비밀번호"}),e.jsx("input",{type:"password",className:"form-control",value:r.currentPassword,onChange:s=>n(a=>({...a,currentPassword:s.target.value}))})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"새 비밀번호"}),e.jsx("input",{type:"password",className:"form-control",value:r.newPassword,placeholder:"8자 이상",onChange:s=>n(a=>({...a,newPassword:s.target.value}))})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"새 비밀번호 확인"}),e.jsx("input",{type:"password",className:"form-control",value:r.confirmPassword,onChange:s=>n(a=>({...a,confirmPassword:s.target.value}))})]}),e.jsx("button",{className:"btn btn-primary",onClick:p,disabled:l||!r.currentPassword||!r.newPassword,children:l?"변경 중...":"비밀번호 변경"})]})]})}export{f as default}; diff --git a/backend/src/main/resources/static/assets/Business-EGnXphuY.js b/backend/src/main/resources/static/assets/Business-EGnXphuY.js new file mode 100644 index 00000000..4af58da6 --- /dev/null +++ b/backend/src/main/resources/static/assets/Business-EGnXphuY.js @@ -0,0 +1 @@ +import{j as e,b as h,a as i,r as j,N as g}from"./index-ChpGil2q.js";/* empty css */const m=[{path:"/business/reference",label:"구축 레퍼런스"},{path:"/business/partner",label:"파트너"}];function p({title:c}){return e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"page-hero",children:e.jsxs("div",{className:"container",children:[e.jsx("span",{className:"section-label",children:"Business"}),e.jsx("h1",{className:"page-hero-title",children:c})]})}),e.jsx("nav",{className:"sub-nav",children:e.jsx("div",{className:"container",children:m.map(a=>e.jsx(g,{to:a.path,className:({isActive:l})=>"sub-nav-item"+(l?" active":""),children:a.label},a.path))})})]})}const t=[{period:"24.12~25.02",client:"엠로",project:"DELL 차세대 CRM 구축",role:"DBA",tech:"Oracle 19C, SQL/PLSQL, Java",category:"금융·제조"},{period:"24.09~25.10",client:"삼성전자",project:"삼성전자 차세대 CRM 구축",role:"DB튜너",tech:"JBOSS, EDB, SQL/PLSQL, Java",category:"대기업"},{period:"24.03~24.06",client:"서울신용보증재단",project:"소상공인 컨설팅시스템 구축",role:"PM",tech:"JSP/Java, Websquare, Spring, Oracle",category:"공공기관"},{period:"23.11~24.02",client:"국민연금관리공단",project:"국민연금 차세대 시스템 구축",role:"AA",tech:"JSP/Java, Nexacro, Spring, CI/CD",category:"공공기관"},{period:"23.08~23.10",client:"헌법재판소",project:"헌법재판소 포털시스템 구축",role:"PM",tech:"Java, Egov, Spring, JEUS",category:"공공기관"},{period:"22.08~23.07",client:"서울신용보증재단",project:"재단 모바일앱 구축",role:"PM",tech:"Java, Nexacro, Spring, EDB",category:"공공기관"},{period:"22.01~22.07",client:"에이텍에이피",project:"통합유지보수관리시스템 개발",role:"PM",tech:"Java, Nexacro, Spring, Tomcat",category:"IT서비스"},{period:"21.10~21.12",client:"헌법재판소",project:"통합보안관제시스템 구축 / DB이관",role:"PM",tech:"Java, Spring, JEUS, Oracle 12c",category:"공공기관"},{period:"20.05~21.09",client:"현대백화점",project:"현대백화점 HKOS 시스템 개발",role:"PM",tech:"Java, Nexacro, Spring, Pro*C",category:"유통·물류"},{period:"20.12~21.04",client:"서울시립대",project:"대학행정정보시스템 성능개선",role:"PL",tech:"Java, Spring, JMeter, JEUS, OZ",category:"교육기관"},{period:"20.07~20.11",client:"에이텍에이피",project:"WMS 공통 프레임워크 구축",role:"PM",tech:"Java, Spring, Nexacro, Oracle",category:"IT서비스"},{period:"20.01~20.06",client:"농협하나로마트",project:"농협 하나로마트 ESL시스템",role:"PM",tech:"C#, Java Spring Batch, REST API",category:"유통·물류"},{period:"19.07~19.12",client:"장보고식자재마트",project:"정산시스템 구축",role:"PM",tech:"Java, Spring, Xplatform, Oracle",category:"유통·물류"},{period:"19.01~19.06",client:"한화갤러리아",project:"갤러리아백화점 PDA 정산시스템",role:"PM",tech:"Java, Spring, Xplatform, Oracle",category:"유통·물류"},{period:"18.07~18.12",client:"이마트",project:"이마트 정산시스템 프로젝트",role:"DA",tech:"Java, Spring, Xplatform, Oracle",category:"유통·물류"},{period:"18.11~18.06",client:"우정사업정보센터",project:"우체국금융 스마트ATM 도입",role:"PMO",tech:"Visual C/C++, TCP/IP 소켓통신",category:"공공기관"},{period:"18.02~18.10",client:"현대백화점",project:"무인POS시스템 구축",role:"PM",tech:"Java, Spring, Xplatform, Oracle",category:"유통·물류"},{period:"17.11~18.01",client:"KOCES",project:"KocesICPos 자동업데이트 런처",role:"개발",tech:"C# .NET, Java/JSP, C/PRO*C",category:"금융·제조"},{period:"15.12~17.10",client:"LG U+",project:"LG U+ VAN 고도화",role:"AA",tech:"Anylink/Tmax, WebLogic, C/PRO*C",category:"통신·금융"},{period:"15.07~15.11",client:"한화S&C",project:"한화그룹 4사 통합 HR시스템",role:"PL",tech:"Java/JSP, Web Service (SOAP), IBSheet",category:"대기업"},{period:"14.11~15.03",client:"참좋은여행",project:"콜센터 어플리케이션 구축",role:"PL",tech:"ASP/.NET, Visual Studio 2012",category:"서비스"},{period:"14.07~14.10",client:"현대캐피탈",project:"현대캐피탈 차세대시스템",role:"PL",tech:"Java/JSP, Web Service, XPlatform",category:"금융·제조"},{period:"14.02~14.06",client:"중소기업청",project:"중소기업 1357 통합콜센터",role:"PL",tech:"Java, Spring, XPlatform, 전자정부FW",category:"공공기관"},{period:"13.08~13.12",client:"삼성전자",project:"삼성전자 품질관리시스템(QWINGS)",role:"PM",tech:"Java, Weblogic, Web Service, MiPlatform",category:"대기업"},{period:"13.03~13.07",client:"대우증권",project:"대우증권 통합인프라시스템",role:"DBA",tech:"Java, Spring, XPlatform, Oracle",category:"통신·금융"},{period:"12.04~13.02",client:"삼성전자서비스",project:"eZone Renewal 프로젝트",role:"PL",tech:"Java, Weblogic, PRO*C, Android",category:"대기업"},{period:"12.01~12.04",client:"농수산식품유통공사",project:"무역통계시스템 구축",role:"DBA",tech:"Java, Spring, Hibernate, 전자정부FW",category:"공공기관"},{period:"11.02~11.12",client:"현대모비스",project:"원가관리시스템 구축",role:"DBA",tech:"Java, Spring, Hibernate, MiPlatform",category:"대기업"},{period:"10.07~11.01",client:"한국전기안전공사",project:"전기안전포털시스템 구축",role:"DBA",tech:"Java, Spring, Hibernate, XPlatform",category:"공공기관"},{period:"09.09~10.04",client:"엽연초생산협동조합",project:"엽연초경작통합시스템 구축",role:"PM",tech:"Java, Struts, i-Batis, Spring",category:"공공기관"},{period:"09.02~09.08",client:"한국전기안전공사",project:"안전점검 고도화",role:"DBA",tech:"Java, Weblogic, 전자정부FW",category:"공공기관"},{period:"08.09~08.12",client:"국민은행",project:"국민은행 차세대 포탈",role:"PL",tech:"Java, AquaLogic, Struts/i-Batis",category:"통신·금융"},{period:"08.06~08.08",client:"한국원자력연료",project:"인사정보(HMS)시스템",role:"DBA",tech:"Java/JSP/JSF, 자체 프레임워크",category:"공공기관"}],x=["전체","공공기관","대기업","유통·물류","통신·금융","금융·제조","교육기관","IT서비스","서비스"],s={공공기관:"#0051A2",대기업:"#7c3aed","유통·물류":"#059669","통신·금융":"#d97706","금융·제조":"#dc2626",교육기관:"#0891b2",IT서비스:"#6366f1",서비스:"#db2777"};function n(){const[c,a]=j.useState("전체"),l=c==="전체"?t:t.filter(r=>r.category===c);return e.jsxs("main",{id:"main-content",className:"inner-page",children:[e.jsx(p,{title:"구축 레퍼런스"}),e.jsx("section",{className:"section",children:e.jsxs("div",{className:"container",children:[e.jsxs("div",{className:"section-header",children:[e.jsx("span",{className:"section-label",children:"Reference"}),e.jsx("h2",{className:"section-title",children:"구축 실적"}),e.jsxs("p",{className:"section-desc",children:["2008년부터 현재까지 국내 주요 기관·기업 ",t.length,"개 프로젝트 성공 수행"]})]}),e.jsx("div",{className:"grid-4",style:{marginBottom:"40px"},children:[{val:`${t.length}+`,label:"총 프로젝트",color:"var(--primary)"},{val:"20+",label:"년 경력",color:"var(--accent)"},{val:"15+",label:"공공기관",color:"#7c3aed"},{val:"10+",label:"대기업·금융",color:"#059669"}].map((r,o)=>e.jsxs("div",{className:"card",style:{padding:"24px",textAlign:"center"},children:[e.jsx("div",{style:{fontSize:"32px",fontWeight:"900",color:r.color},children:r.val}),e.jsx("p",{style:{fontSize:"13px",color:"var(--gray-500)",marginTop:"6px"},children:r.label})]},o))}),e.jsx("div",{className:"ref-filters",children:x.map(r=>e.jsx("button",{className:`ref-filter-btn ${c===r?"active":""}`,onClick:()=>a(r),children:r},r))}),e.jsx("div",{className:"ref-table-wrap",children:e.jsxs("table",{className:"ref-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"기간"}),e.jsx("th",{children:"고객사"}),e.jsx("th",{children:"프로젝트명"}),e.jsx("th",{children:"역할"}),e.jsx("th",{children:"주요기술"}),e.jsx("th",{children:"분야"})]})}),e.jsx("tbody",{children:l.map((r,o)=>e.jsxs("tr",{children:[e.jsx("td",{className:"ref-period",children:r.period}),e.jsx("td",{className:"ref-client",children:r.client}),e.jsx("td",{className:"ref-project",children:r.project}),e.jsx("td",{children:e.jsx("span",{className:"ref-role",children:r.role})}),e.jsx("td",{className:"ref-tech",children:r.tech}),e.jsx("td",{children:e.jsx("span",{className:"ref-cat-badge",style:{background:s[r.category]+"18",color:s[r.category]},children:r.category})})]},o))})]})})]})})]})}const S=[{name:"Oracle",logo:"🔴",desc:"Oracle DB 공식 파트너 — Oracle 19c 전문 DBA 인증",tier:"Gold"},{name:"Red Hat",logo:"🎩",desc:"RHEL·OpenShift 파트너 — 리눅스 인프라 구축",tier:"Silver"},{name:"JEUS (TmaxSoft)",logo:"⚙️",desc:"국산 WAS JEUS/Tmax 공식 파트너",tier:"Gold"},{name:"Tibero",logo:"🗄️",desc:"Tibero DBMS 공식 파트너 — 공공기관 DB 전환",tier:"Gold"},{name:"Samsung SDS",logo:"💼",desc:"삼성SDS 협력사 — 삼성전자 CRM/품질 시스템 공동 수행",tier:"Partner"},{name:"Nexacro",logo:"🖥️",desc:"투비소프트 Nexacro 공식 파트너 — UI 개발 전문",tier:"Silver"},{name:"OZ Report",logo:"📊",desc:"OZ e-Form 공식 파트너 — 공공 전자문서 솔루션",tier:"Silver"},{name:"Ollama",logo:"🤖",desc:"온프레미스 LLM 파트너 — GUARDiA AI 엔진 공급사",tier:"Tech"}],d={Gold:"#d97706",Silver:"#6b7280",Partner:"#0051A2",Tech:"#7c3aed"};function v(){return e.jsxs("main",{id:"main-content",className:"inner-page",children:[e.jsx(p,{title:"파트너"}),e.jsx("section",{className:"section",children:e.jsxs("div",{className:"container",children:[e.jsxs("div",{className:"section-header",children:[e.jsx("span",{className:"section-label",children:"Partners"}),e.jsx("h2",{className:"section-title",children:"기술 파트너"}),e.jsx("p",{className:"section-desc",children:"최고의 기술 파트너와 함께 최선의 솔루션을 제공합니다"})]}),e.jsx("div",{className:"grid-4",children:S.map((c,a)=>e.jsxs("div",{className:"card partner-card",children:[e.jsx("div",{className:"partner-logo",children:c.logo}),e.jsxs("div",{className:"partner-tier",style:{background:d[c.tier]+"1a",color:d[c.tier]},children:[c.tier," Partner"]}),e.jsx("h3",{className:"partner-name",children:c.name}),e.jsx("p",{className:"partner-desc",children:c.desc})]},a))}),e.jsxs("div",{className:"partner-cta",children:[e.jsx("h3",{children:"파트너십 문의"}),e.jsx("p",{children:"지오정보기술과 기술 파트너십을 맺고 싶으신 기업은 아래로 연락 주십시오."}),e.jsx("a",{href:"/support/contact?type=사업제안",className:"btn btn-primary btn-lg",children:"파트너십 제안하기"})]})]})})]})}function y(){return e.jsxs(h,{children:[e.jsx(i,{path:"reference",element:e.jsx(n,{})}),e.jsx(i,{path:"partner",element:e.jsx(v,{})}),e.jsx(i,{path:"*",element:e.jsx(n,{})})]})}export{y as default}; diff --git a/backend/src/main/resources/static/assets/Business-EM7OeA4c.css b/backend/src/main/resources/static/assets/Business-EM7OeA4c.css new file mode 100644 index 00000000..67e93404 --- /dev/null +++ b/backend/src/main/resources/static/assets/Business-EM7OeA4c.css @@ -0,0 +1 @@ +.ref-filters{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:24px}.ref-filter-btn{padding:7px 18px;border-radius:20px;border:1px solid var(--gray-200);font-size:13px;font-weight:500;color:var(--gray-600);cursor:pointer;transition:all var(--fast) var(--ease);background:var(--white)}.ref-filter-btn:hover{border-color:var(--primary);color:var(--primary)}.ref-filter-btn.active{background:var(--primary);border-color:var(--primary);color:#fff}.ref-table-wrap{overflow-x:auto;border-radius:12px;border:1px solid var(--gray-200)}.ref-table{width:100%;border-collapse:collapse;min-width:800px}.ref-table th{background:var(--secondary);color:#fffc;padding:14px 16px;text-align:left;font-size:12px;font-weight:600;letter-spacing:.5px}.ref-table td{padding:13px 16px;font-size:13px;border-bottom:1px solid var(--gray-100);vertical-align:middle}.ref-table tr:last-child td{border-bottom:none}.ref-table tr:hover td{background:var(--gray-50)}.ref-period{color:var(--gray-500);font-size:12px;white-space:nowrap}.ref-client{font-weight:700;color:var(--gray-800);white-space:nowrap}.ref-project{color:var(--gray-700)}.ref-role{padding:3px 10px;border-radius:12px;font-size:11px;font-weight:700;background:var(--primary-light);color:var(--primary);white-space:nowrap}.ref-tech{font-size:12px;color:var(--gray-500)}.ref-cat-badge{padding:3px 10px;border-radius:12px;font-size:11px;font-weight:600;white-space:nowrap}.partner-card{padding:32px 24px;text-align:center}.partner-logo{font-size:48px;margin-bottom:12px}.partner-tier{display:inline-block;padding:3px 12px;border-radius:12px;font-size:11px;font-weight:700;margin-bottom:12px}.partner-name{font-size:16px;font-weight:700;color:var(--gray-900);margin-bottom:10px}.partner-desc{font-size:13px;color:var(--gray-600);line-height:1.6}.partner-cta{margin-top:64px;text-align:center;padding:56px;background:linear-gradient(135deg,var(--primary-light),rgba(0,163,224,.08));border-radius:16px;border:1px solid var(--gray-200)}.partner-cta h3{font-size:24px;font-weight:800;margin-bottom:12px}.partner-cta p{color:var(--gray-600);margin-bottom:24px;font-size:15px} diff --git a/backend/src/main/resources/static/assets/Common-BmvLh5lB.css b/backend/src/main/resources/static/assets/Common-BmvLh5lB.css new file mode 100644 index 00000000..36fe3cbf --- /dev/null +++ b/backend/src/main/resources/static/assets/Common-BmvLh5lB.css @@ -0,0 +1 @@ +.inner-page{padding-top:var(--header-h)}.page-hero{background:linear-gradient(135deg,var(--secondary),var(--primary-dark));padding:60px 0;color:#fff}.page-hero-title{font-size:40px;font-weight:900;margin:8px 0 12px}.page-hero p{color:#ffffffbf;font-size:16px} diff --git a/backend/src/main/resources/static/assets/Company-BOdWAIQ4.js b/backend/src/main/resources/static/assets/Company-BOdWAIQ4.js new file mode 100644 index 00000000..aaf32225 --- /dev/null +++ b/backend/src/main/resources/static/assets/Company-BOdWAIQ4.js @@ -0,0 +1 @@ +import{j as s,b as t,a as l,N as d}from"./index-ChpGil2q.js";/* empty css */const o=[{path:"/company/greeting",label:"CEO 인사말"},{path:"/company/history",label:"연혁"},{path:"/company/organization",label:"조직도"},{path:"/company/ci",label:"CI 소개"},{path:"/company/location",label:"오시는 길"}];function n({title:e}){return s.jsxs(s.Fragment,{children:[s.jsx("div",{className:"page-hero",children:s.jsxs("div",{className:"container",children:[s.jsx("span",{className:"section-label",children:"Company"}),s.jsx("h1",{className:"page-hero-title",children:e})]})}),s.jsx("nav",{className:"sub-nav",children:s.jsx("div",{className:"container",children:o.map(a=>s.jsx(d,{to:a.path,className:({isActive:i})=>"sub-nav-item"+(i?" active":""),children:a.label},a.path))})})]})}function r(){return s.jsxs("main",{id:"main-content",className:"inner-page",children:[s.jsx(n,{title:"CEO 인사말"}),s.jsx("section",{className:"section",children:s.jsxs("div",{className:"container",style:{maxWidth:"860px"},children:[s.jsxs("div",{className:"ceo-wrap",children:[s.jsxs("div",{className:"ceo-photo",children:[s.jsx("div",{className:"ceo-avatar",children:s.jsx("span",{children:"CEO"})}),s.jsx("p",{className:"ceo-name",children:"대표이사"}),s.jsx("p",{className:"ceo-sign",children:"(주)지오정보기술"})]}),s.jsxs("div",{className:"ceo-text",children:[s.jsxs("h2",{children:["안녕하십니까,",s.jsx("br",{}),"(주)지오정보기술 대표이사입니다."]}),s.jsx("div",{className:"divider divider-left",style:{margin:"20px 0 28px"}}),["저희 (주)지오정보기술은 2000년 창립 이래 20년 이상 공공기관 및 대기업 IT 전문 서비스 기업으로 성장해 왔습니다. 삼성전자, 현대백화점, 국민연금, 헌법재판소 등 국내 주요 기관·기업의 핵심 시스템을 성공적으로 구축·운영한 풍부한 경험을 보유하고 있습니다.",'최근에는 GUARDiA ITSM 플랫폼을 통해 "AI 기반 인프라 자율 운영"이라는 새로운 패러다임을 제시하고 있습니다. 메신저 한 줄 명령으로 1,000개 이상의 관공서 레거시 인프라를 자동화하는 혁신적인 솔루션으로, 대상 서버에 별도 소프트웨어 설치 없이 표준 SSH/SFTP 프로토콜만으로 운영 자동화를 실현합니다.',"앞으로도 고객의 성공이 곧 저희의 성공이라는 신념 아래, 최고의 기술력과 서비스로 보답하겠습니다. 언제나 여러분 곁에서 디지털 혁신의 파트너가 되겠습니다.","감사합니다."].map((e,a)=>s.jsx("p",{className:"ceo-para",children:e},a))]})]}),s.jsxs("div",{style:{marginTop:"72px"},children:[s.jsxs("div",{className:"section-header",children:[s.jsx("span",{className:"section-label",children:"Core Values"}),s.jsx("h2",{className:"section-title",children:"핵심 가치"})]}),s.jsx("div",{className:"grid-4",children:[{icon:"🎯",title:"고객 중심",desc:"고객의 성공을 최우선으로 생각하며 최적의 솔루션을 제공합니다"},{icon:"🚀",title:"기술 혁신",desc:"AI·클라우드 최신 기술로 고객의 디지털 전환을 선도합니다"},{icon:"🤝",title:"신뢰와 책임",desc:"20년 이상 축적된 신뢰로 책임감 있는 서비스를 제공합니다"},{icon:"🌱",title:"지속 성장",desc:"구성원과 고객이 함께 성장하는 지속 가능한 파트너십을 추구합니다"}].map((e,a)=>s.jsxs("div",{className:"card",style:{padding:"32px 24px",textAlign:"center"},children:[s.jsx("div",{style:{fontSize:"40px",marginBottom:"16px"},children:e.icon}),s.jsx("h3",{style:{fontSize:"18px",fontWeight:"700",marginBottom:"12px"},children:e.title}),s.jsx("p",{style:{fontSize:"14px",color:"var(--gray-600)",lineHeight:"1.7"},children:e.desc})]},a))})]})]})})]})}const m=[{year:"2026",items:["GUARDiA ITSM v2.0 출시 — AI ChatOps 오케스트레이션 플랫폼","GS인증 1등급 신청 준비 완료 (TTA 심사 예정)","공공기관 1,000개 이상 멀티테넌트 지원 목표 달성"]},{year:"2025",items:["삼성전자 차세대 CRM 구축 (DB Migration / DA / 튜닝)","GUARDiA ITSM v1.0 베타 서비스 개시","AI 기반 인프라 자동화 특허 출원"]},{year:"2024",items:["DELL 차세대 CRM 구축 — DBA 역할 수행 (엠로)","소상공인컨설팅시스템 구축 (서울신용보증재단, PM)","국민연금 차세대 시스템 구축 (AA)"]},{year:"2023",items:["헌법재판소 포털시스템 구축 (PM)","서울신용보증재단 모바일앱 구축 완료 (PM)"]},{year:"2022",items:["에이텍에이피 통합유지보수관리시스템 개발 (PM)","헌법재판소 통합보안관제시스템 구축 (PM)"]},{year:"2020–2021",items:["현대백화점 HKOS 시스템 개발/구축 (PM)","서울시립대 대학행정정보시스템 성능 개선 (PL)","농협 하나로마트 ESL 시스템 구축 (PM)"]},{year:"2018–2019",items:["이마트 정산시스템 프로젝트 (DA)","우체국금융 스마트ATM 도입 (PMO)","현대백화점 무인POS시스템 구축 (PM)","갤러리아백화점 PDA 정산시스템 (PM)"]},{year:"2015–2017",items:["LG U+ VAN 고도화 — 승인시스템 개발 FEP/AP/BEP (AA)","한화그룹 4사 통합 HR시스템 구축 (PL)","참좋은여행 콜센터 어플리케이션 구축 (PL)"]},{year:"2013–2014",items:["삼성전자 품질관리시스템(QWINGS) 구축 (PM)","대우증권 통합인프라시스템 (DBA)","현대캐피탈 차세대시스템 (PL)","중소기업 1357 통합콜센터 구축 (PL)"]},{year:"2010–2012",items:["삼성전자서비스 eZone 갱신 (PL)","현대모비스 원가관리시스템 (DBA)","한국전기안전공사 전기안전포털시스템 (DBA)"]},{year:"2008–2009",items:["국민은행 차세대 포탈 구축 (PL)","한국원자력연료 인사정보(HMS)시스템 (DBA)","한국전기안전공사 안전점검 고도화 (DBA)"]},{year:"2000",items:["(주)지오정보기술 창립","공공기관 IT 인프라 서비스 개시"]}];function x(){return s.jsxs("main",{id:"main-content",className:"inner-page",children:[s.jsx(n,{title:"연혁"}),s.jsx("section",{className:"section",children:s.jsxs("div",{className:"container",style:{maxWidth:"900px"},children:[s.jsxs("div",{className:"section-header",children:[s.jsx("span",{className:"section-label",children:"History"}),s.jsx("h2",{className:"section-title",children:"20년+ 성장의 역사"}),s.jsx("p",{className:"section-desc",children:"2000년 창립 이래 국내 주요 기관·기업과 함께 성장해 왔습니다"})]}),s.jsx("div",{className:"timeline",children:m.map((e,a)=>s.jsxs("div",{className:"timeline-row",children:[s.jsx("div",{className:"timeline-year",children:e.year}),s.jsx("div",{className:"timeline-dot"}),s.jsx("div",{className:"timeline-content",children:e.items.map((i,c)=>s.jsxs("div",{className:"timeline-item",children:[s.jsx("span",{className:"timeline-bullet"}),i]},c))})]},a))})]})})]})}function h(){return s.jsxs("main",{id:"main-content",className:"inner-page",children:[s.jsx(n,{title:"조직도"}),s.jsx("section",{className:"section",children:s.jsxs("div",{className:"container",style:{maxWidth:"960px"},children:[s.jsxs("div",{className:"section-header",children:[s.jsx("span",{className:"section-label",children:"Organization"}),s.jsx("h2",{className:"section-title",children:"조직 구성"})]}),s.jsxs("div",{className:"org-chart",children:[s.jsx("div",{className:"org-top",children:s.jsx("div",{className:"org-box ceo",children:"대표이사"})}),s.jsx("div",{className:"org-line-v"}),s.jsx("div",{className:"org-depts",children:[{name:"개발본부",color:"var(--primary)",teams:["AI개발팀","플랫폼개발팀","프론트엔드팀"]},{name:"기술본부",color:"var(--accent)",teams:["인프라팀","DBA팀","보안팀"]},{name:"PM본부",color:"#7c3aed",teams:["SI사업팀","SM운영팀","PMO팀"]},{name:"경영지원본부",color:"#059669",teams:["경영기획팀","영업팀","인사·총무팀"]}].map((e,a)=>s.jsxs("div",{className:"org-dept-col",children:[s.jsx("div",{className:"org-line-h"}),s.jsx("div",{className:"org-line-v-short"}),s.jsx("div",{className:"org-box dept",style:{borderColor:e.color,color:e.color},children:e.name}),s.jsx("div",{className:"org-teams",children:e.teams.map((i,c)=>s.jsx("div",{className:"org-box team",children:i},c))})]},a))})]}),s.jsx("div",{className:"grid-4",style:{marginTop:"64px"},children:[{label:"전체 임직원",value:"50+",unit:"명"},{label:"개발 인력",value:"70",unit:"%"},{label:"평균 경력",value:"8",unit:"년+"},{label:"국가 공인 자격",value:"30+",unit:"개"}].map((e,a)=>s.jsxs("div",{className:"card",style:{padding:"32px",textAlign:"center"},children:[s.jsxs("div",{style:{fontSize:"36px",fontWeight:"900",color:"var(--primary)"},children:[e.value,s.jsx("span",{style:{fontSize:"18px"},children:e.unit})]}),s.jsx("p",{style:{marginTop:"8px",color:"var(--gray-600)",fontSize:"14px"},children:e.label})]},a))})]})})]})}function j(){return s.jsxs("main",{id:"main-content",className:"inner-page",children:[s.jsx(n,{title:"CI 소개"}),s.jsx("section",{className:"section",children:s.jsxs("div",{className:"container",style:{maxWidth:"900px"},children:[s.jsxs("div",{className:"section-header",children:[s.jsx("span",{className:"section-label",children:"Corporate Identity"}),s.jsx("h2",{className:"section-title",children:"브랜드 아이덴티티"}),s.jsx("p",{className:"section-desc",children:"지오정보기술의 브랜드는 신뢰·혁신·전문성을 상징합니다"})]}),s.jsxs("div",{className:"ci-section",children:[s.jsx("h3",{className:"ci-title",children:"로고 시스템"}),s.jsxs("div",{className:"ci-logo-wrap",children:[s.jsxs("div",{className:"ci-logo-box dark",children:[s.jsxs("div",{className:"ci-logo-text-wrap",children:[s.jsx("span",{className:"ci-logo-mark",children:"GEO"}),s.jsx("span",{className:"ci-logo-sub",children:"정보기술"})]}),s.jsx("p",{className:"ci-logo-label",children:"다크 배경용"})]}),s.jsxs("div",{className:"ci-logo-box light",children:[s.jsxs("div",{className:"ci-logo-text-wrap",children:[s.jsx("span",{className:"ci-logo-mark",style:{color:"var(--primary)"},children:"GEO"}),s.jsx("span",{className:"ci-logo-sub",style:{color:"var(--gray-700)"},children:"정보기술"})]}),s.jsx("p",{className:"ci-logo-label",style:{color:"var(--gray-500)"},children:"라이트 배경용"})]})]})]}),s.jsxs("div",{className:"ci-section",children:[s.jsx("h3",{className:"ci-title",children:"브랜드 컬러"}),s.jsx("div",{className:"ci-colors",children:[{name:"Primary Blue",hex:"#0051A2",cmyk:"C100 M50 Y0 K37",usage:"주요 UI·버튼·강조"},{name:"Accent Blue",hex:"#00A3E0",cmyk:"C100 M28 Y0 K12",usage:"포인트·링크·아이콘"},{name:"Dark Navy",hex:"#1A1A2E",cmyk:"C40 M40 Y0 K82",usage:"헤더·배경·텍스트"},{name:"Pure White",hex:"#FFFFFF",cmyk:"C0 M0 Y0 K0",usage:"배경·반전 텍스트"}].map((e,a)=>s.jsxs("div",{className:"ci-color-card",children:[s.jsx("div",{className:"ci-color-swatch",style:{background:e.hex,border:e.hex==="#FFFFFF"?"1px solid #eee":"none"}}),s.jsxs("div",{className:"ci-color-info",children:[s.jsx("strong",{children:e.name}),s.jsx("span",{className:"ci-hex",children:e.hex}),s.jsx("span",{className:"ci-cmyk",children:e.cmyk}),s.jsx("span",{className:"ci-usage",children:e.usage})]})]},a))})]}),s.jsxs("div",{className:"ci-section",children:[s.jsx("h3",{className:"ci-title",children:"브랜드 슬로건"}),s.jsxs("div",{className:"ci-slogan-wrap",children:[s.jsx("p",{className:"ci-slogan-main",children:'"공공기관 IT, 지오정보기술과 함께"'}),s.jsx("p",{className:"ci-slogan-sub",children:"20년 신뢰의 기술력으로 AI 인프라 혁신을 이끕니다"})]})]})]})})]})}function p(){return s.jsxs("main",{id:"main-content",className:"inner-page",children:[s.jsx(n,{title:"오시는 길"}),s.jsx("section",{className:"section",children:s.jsxs("div",{className:"container",style:{maxWidth:"960px"},children:[s.jsxs("div",{className:"section-header",children:[s.jsx("span",{className:"section-label",children:"Location"}),s.jsx("h2",{className:"section-title",children:"오시는 길"})]}),s.jsx("div",{className:"map-wrap",children:s.jsxs("div",{className:"map-placeholder",children:[s.jsx("div",{className:"map-pin",children:"📍"}),s.jsx("p",{children:"(주)지오정보기술"}),s.jsx("p",{style:{fontSize:"13px",color:"var(--gray-400)",marginTop:"8px"},children:"서울특별시 강서구 양천로 570"})]})}),s.jsxs("div",{className:"location-grid",children:[s.jsxs("div",{className:"card",style:{padding:"36px"},children:[s.jsx("h3",{className:"loc-office-title",children:"📍 본사"}),s.jsx("table",{className:"loc-table",children:s.jsxs("tbody",{children:[s.jsxs("tr",{children:[s.jsx("th",{children:"주소"}),s.jsxs("td",{children:["서울특별시 강서구 양천로 570",s.jsx("br",{}),"NH서울타워 5층"]})]}),s.jsxs("tr",{children:[s.jsx("th",{children:"대표전화"}),s.jsx("td",{children:"02-784-9271"})]}),s.jsxs("tr",{children:[s.jsx("th",{children:"팩스"}),s.jsx("td",{children:"02-784-9272"})]}),s.jsxs("tr",{children:[s.jsx("th",{children:"이메일"}),s.jsx("td",{children:"info@zioinfo.co.kr"})]}),s.jsxs("tr",{children:[s.jsx("th",{children:"운영시간"}),s.jsx("td",{children:"평일 09:00 ~ 18:00 (점심 12:00~13:00)"})]})]})})]}),s.jsxs("div",{className:"card",style:{padding:"36px"},children:[s.jsx("h3",{className:"loc-office-title",children:"🚇 교통 안내"}),s.jsx("div",{className:"transport-list",children:[{type:"지하철",icon:"🚇",lines:["5호선 발산역 1번 출구 도보 5분","9호선 마곡나루역 3번 출구 도보 10분"]},{type:"버스",icon:"🚌",lines:["강서05, 강서06 — 강서구청 정류장 하차","60, 62, 604 — 발산역 하차"]},{type:"자가용",icon:"🚗",lines:["올림픽대로 → 강서IC → 양천로 방면","주차 가능 (방문 전 사전 연락 권장)"]}].map((e,a)=>s.jsxs("div",{className:"transport-item",children:[s.jsxs("div",{className:"transport-header",children:[s.jsx("span",{children:e.icon}),s.jsx("strong",{children:e.type})]}),e.lines.map((i,c)=>s.jsx("p",{children:i},c))]},a))})]})]})]})})]})}function g(){return s.jsxs(t,{children:[s.jsx(l,{path:"greeting",element:s.jsx(r,{})}),s.jsx(l,{path:"history",element:s.jsx(x,{})}),s.jsx(l,{path:"organization",element:s.jsx(h,{})}),s.jsx(l,{path:"ci",element:s.jsx(j,{})}),s.jsx(l,{path:"location",element:s.jsx(p,{})}),s.jsx(l,{path:"*",element:s.jsx(r,{})})]})}export{g as default}; diff --git a/backend/src/main/resources/static/assets/Company-qD6qaVvP.css b/backend/src/main/resources/static/assets/Company-qD6qaVvP.css new file mode 100644 index 00000000..77a1d202 --- /dev/null +++ b/backend/src/main/resources/static/assets/Company-qD6qaVvP.css @@ -0,0 +1 @@ +.sub-nav{background:var(--white);border-bottom:1px solid var(--gray-200)}.sub-nav .container{display:flex;gap:0;overflow-x:auto}.sub-nav-item{padding:14px 22px;font-size:14px;font-weight:500;color:var(--gray-600);white-space:nowrap;border-bottom:2px solid transparent;transition:all var(--fast) var(--ease)}.sub-nav-item:hover{color:var(--primary)}.sub-nav-item.active{color:var(--primary);border-bottom-color:var(--primary);font-weight:700}.ceo-wrap{display:grid;grid-template-columns:220px 1fr;gap:60px;align-items:start}.ceo-photo{text-align:center}.ceo-avatar{width:160px;height:160px;border-radius:50%;background:linear-gradient(135deg,var(--primary),var(--accent));display:flex;align-items:center;justify-content:center;font-size:28px;font-weight:900;color:#fff;margin:0 auto 16px}.ceo-name{font-size:18px;font-weight:700;color:var(--gray-800)}.ceo-sign{font-size:13px;color:var(--gray-500);margin-top:4px}.ceo-text h2{font-size:26px;font-weight:900;color:var(--gray-900);line-height:1.4}.ceo-para{font-size:15px;line-height:1.9;color:var(--gray-700);margin-bottom:18px}.timeline{position:relative;padding-left:0}.timeline-row{display:grid;grid-template-columns:120px 24px 1fr;gap:0 24px;margin-bottom:40px;align-items:start}.timeline-year{font-size:22px;font-weight:900;color:var(--primary);text-align:right;padding-top:2px;line-height:1.2}.timeline-dot{width:16px;height:16px;border-radius:50%;background:var(--primary);border:3px solid var(--primary-light);margin-top:4px;position:relative;flex-shrink:0}.timeline-dot:after{content:"";position:absolute;top:100%;left:50%;transform:translate(-50%);width:2px;height:calc(100% + 40px);background:var(--gray-200)}.timeline-row:last-child .timeline-dot:after{display:none}.timeline-content{padding-bottom:8px}.timeline-item{display:flex;gap:10px;font-size:15px;color:var(--gray-700);margin-bottom:8px;line-height:1.6;align-items:flex-start}.timeline-bullet{width:6px;height:6px;border-radius:50%;background:var(--accent);flex-shrink:0;margin-top:7px}.org-chart{text-align:center}.org-top{display:flex;justify-content:center;margin-bottom:0}.org-box{padding:14px 28px;border-radius:10px;font-weight:700;font-size:15px;display:inline-flex;align-items:center;justify-content:center}.org-box.ceo{background:var(--secondary);color:#fff;min-width:160px;font-size:17px}.org-box.dept{background:var(--white);border:2px solid;min-width:140px;font-size:14px}.org-box.team{background:var(--gray-50);border:1px solid var(--gray-200);color:var(--gray-700);font-size:13px;padding:10px 16px;margin-bottom:8px;min-width:120px;font-weight:500}.org-line-v{width:2px;height:40px;background:var(--gray-300);margin:0 auto}.org-line-v-short{width:2px;height:24px;background:var(--gray-300);margin:0 auto}.org-depts{display:flex;justify-content:center;gap:32px;position:relative}.org-dept-col{display:flex;flex-direction:column;align-items:center}.org-teams{display:flex;flex-direction:column;align-items:center;margin-top:12px}.org-line-h{width:100%;height:2px;background:var(--gray-300)}.ci-section{margin-bottom:56px}.ci-title{font-size:20px;font-weight:800;color:var(--gray-900);margin-bottom:24px;padding-bottom:12px;border-bottom:2px solid var(--gray-200)}.ci-logo-wrap{display:flex;gap:24px;flex-wrap:wrap}.ci-logo-box{flex:1;min-width:200px;padding:48px 32px;border-radius:12px;display:flex;flex-direction:column;align-items:center;gap:16px}.ci-logo-box.dark{background:var(--secondary)}.ci-logo-box.light{background:var(--gray-50);border:1px solid var(--gray-200)}.ci-logo-text-wrap{display:flex;flex-direction:column;align-items:center;gap:4px}.ci-logo-mark{font-size:32px;font-weight:900;color:var(--accent);letter-spacing:4px}.ci-logo-sub{font-size:14px;font-weight:600;color:#ffffffb3;letter-spacing:2px}.ci-logo-label{font-size:12px;color:#ffffff80}.ci-colors{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}.ci-color-card{border:1px solid var(--gray-200);border-radius:10px;overflow:hidden}.ci-color-swatch{height:100px}.ci-color-info{padding:16px;display:flex;flex-direction:column;gap:4px}.ci-color-info strong{font-size:14px;font-weight:700}.ci-hex{font-size:12px;font-family:monospace;color:var(--primary)}.ci-cmyk{font-size:11px;color:var(--gray-500)}.ci-usage{font-size:12px;color:var(--gray-600)}.ci-slogan-wrap{background:linear-gradient(135deg,var(--secondary),var(--primary-dark));border-radius:16px;padding:56px;text-align:center}.ci-slogan-main{font-size:28px;font-weight:900;color:#fff;margin-bottom:12px}.ci-slogan-sub{font-size:16px;color:#ffffffb3}.map-wrap{margin-bottom:32px}.map-placeholder{height:320px;background:var(--gray-100);border-radius:16px;display:flex;flex-direction:column;align-items:center;justify-content:center;border:1px solid var(--gray-200);color:var(--gray-600);font-size:16px;font-weight:600}.map-pin{font-size:48px;margin-bottom:12px}.location-grid{display:grid;grid-template-columns:1fr 1fr;gap:24px}.loc-office-title{font-size:18px;font-weight:700;margin-bottom:20px;color:var(--gray-900)}.loc-table{width:100%;border-collapse:collapse}.loc-table th{width:90px;text-align:left;font-size:13px;color:var(--gray-500);font-weight:600;padding:10px 0;vertical-align:top}.loc-table td{font-size:14px;color:var(--gray-700);padding:10px 0;line-height:1.6;border-bottom:1px solid var(--gray-100)}.transport-list{display:flex;flex-direction:column;gap:20px}.transport-header{display:flex;gap:8px;align-items:center;margin-bottom:6px}.transport-header strong{font-size:14px;font-weight:700;color:var(--primary)}.transport-item p{font-size:13px;color:var(--gray-600);padding-left:24px;line-height:1.7}@media (max-width: 768px){.ceo-wrap{grid-template-columns:1fr}.timeline-row{grid-template-columns:80px 20px 1fr;gap:0 16px}.timeline-year{font-size:16px}.org-depts{flex-direction:column;align-items:center;gap:24px}.ci-colors{grid-template-columns:repeat(2,1fr)}.location-grid{grid-template-columns:1fr}} diff --git a/backend/src/main/resources/static/assets/Contact-C2ZwoM3_.css b/backend/src/main/resources/static/assets/Contact-C2ZwoM3_.css new file mode 100644 index 00000000..efc5836a --- /dev/null +++ b/backend/src/main/resources/static/assets/Contact-C2ZwoM3_.css @@ -0,0 +1 @@ +.contact-page{padding-top:var(--header-h)}.page-hero{background:linear-gradient(135deg,var(--secondary),var(--primary-dark));padding:60px 0;color:#fff}.page-hero-title{font-size:40px;font-weight:900;margin:8px 0 12px}.page-hero p{color:#ffffffbf;font-size:16px}.contact-grid{display:grid;grid-template-columns:340px 1fr;gap:48px;align-items:start}.contact-info h2{font-size:22px;font-weight:700;margin-bottom:28px}.info-item{display:flex;gap:16px;margin-bottom:24px;align-items:flex-start}.info-icon{font-size:24px}.info-item strong{display:block;font-size:13px;font-weight:700;color:var(--gray-500);margin-bottom:2px}.info-item p{font-size:15px;color:var(--gray-800)}.contact-form{padding:36px}.contact-form h2{font-size:22px;font-weight:700;margin-bottom:24px}.form-alert{padding:12px 16px;border-radius:var(--radius-sm);font-size:14px;margin-bottom:16px}.form-alert.success{background:#d1fae5;color:#065f46}.form-alert.error{background:#fee2e2;color:#991b1b}.form-row{display:grid;grid-template-columns:1fr 1fr;gap:16px}.form-group{display:flex;flex-direction:column;gap:6px;margin-bottom:16px}.form-group label{font-size:13px;font-weight:600;color:var(--gray-700)}.required{color:var(--danger)}.form-group input,.form-group select,.form-group textarea{padding:10px 14px;border:1px solid var(--gray-200);border-radius:var(--radius-sm);font-size:14px;font-family:inherit;transition:border-color var(--fast);outline:none}.form-group input:focus,.form-group select:focus,.form-group textarea:focus{border-color:var(--primary);box-shadow:0 0 0 3px #0051a21a}.privacy-agree{display:flex;align-items:center;gap:10px;font-size:13px;color:var(--gray-600);margin-bottom:20px;cursor:pointer}.privacy-agree a{color:var(--primary)}@media (max-width: 1024px){.contact-grid{grid-template-columns:1fr}}@media (max-width: 768px){.form-row{grid-template-columns:1fr}} diff --git a/backend/src/main/resources/static/assets/Contact-C6p_tBWi.js b/backend/src/main/resources/static/assets/Contact-C6p_tBWi.js new file mode 100644 index 00000000..f6d61405 --- /dev/null +++ b/backend/src/main/resources/static/assets/Contact-C6p_tBWi.js @@ -0,0 +1 @@ +import{r as i,j as e}from"./index-ChpGil2q.js";import{a as j}from"./index-DcNlVx-A.js";function y(){const[a,t]=i.useState({name:"",email:"",phone:"",category:"제품문의",subject:"",content:"",agreePrivacy:!1}),[r,l]=i.useState(null),[o,d]=i.useState(!1),s=n=>{const{name:c,value:m,type:p,checked:x}=n.target;t(u=>({...u,[c]:p==="checkbox"?x:m}))},h=async n=>{if(n.preventDefault(),!a.agreePrivacy){l({type:"error",msg:"개인정보 수집·이용에 동의해주세요."});return}d(!0);try{await j.post("/api/inquiry",a),l({type:"success",msg:"문의가 접수되었습니다. 빠른 시일 내에 연락드리겠습니다."}),t({name:"",email:"",phone:"",category:"제품문의",subject:"",content:"",agreePrivacy:!1})}catch{l({type:"error",msg:"문의 접수 중 오류가 발생했습니다. 잠시 후 다시 시도해주세요."})}finally{d(!1)}};return e.jsxs("main",{id:"main-content",className:"contact-page",children:[e.jsx("div",{className:"page-hero",children:e.jsxs("div",{className:"container",children:[e.jsx("span",{className:"section-label",children:"Contact Us"}),e.jsx("h1",{className:"page-hero-title",children:"문의하기"}),e.jsx("p",{children:"GUARDiA ITSM 도입 문의 및 제품 상담을 받아드립니다."})]})}),e.jsx("section",{className:"section",children:e.jsxs("div",{className:"container contact-grid",children:[e.jsxs("div",{className:"contact-info",children:[e.jsx("h2",{children:"연락처 정보"}),[{icon:"📞",label:"대표전화",value:"02-000-0000"},{icon:"✉️",label:"이메일",value:"info@zioinfo.co.kr"},{icon:"🕐",label:"운영시간",value:"평일 09:00 ~ 18:00"},{icon:"📍",label:"주소",value:"서울특별시"}].map((n,c)=>e.jsxs("div",{className:"info-item",children:[e.jsx("span",{className:"info-icon",children:n.icon}),e.jsxs("div",{children:[e.jsx("strong",{children:n.label}),e.jsx("p",{children:n.value})]})]},c))]}),e.jsxs("form",{className:"contact-form card",onSubmit:h,children:[e.jsx("h2",{children:"온라인 문의"}),r&&e.jsxs("div",{className:`form-alert ${r.type}`,children:[r.type==="success"?"✅":"❌"," ",r.msg]}),e.jsxs("div",{className:"form-row",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{htmlFor:"name",children:["성함 ",e.jsx("span",{className:"required",children:"*"})]}),e.jsx("input",{id:"name",name:"name",type:"text",required:!0,value:a.name,onChange:s,placeholder:"홍길동"})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"phone",children:"연락처"}),e.jsx("input",{id:"phone",name:"phone",type:"tel",value:a.phone,onChange:s,placeholder:"010-0000-0000"})]})]}),e.jsxs("div",{className:"form-row",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{htmlFor:"email",children:["이메일 ",e.jsx("span",{className:"required",children:"*"})]}),e.jsx("input",{id:"email",name:"email",type:"email",required:!0,value:a.email,onChange:s,placeholder:"your@email.com"})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"category",children:"문의 유형"}),e.jsxs("select",{id:"category",name:"category",value:a.category,onChange:s,children:[e.jsx("option",{children:"제품문의"}),e.jsx("option",{children:"데모 신청"}),e.jsx("option",{children:"기술지원"}),e.jsx("option",{children:"사업제안"}),e.jsx("option",{children:"채용문의"}),e.jsx("option",{children:"기타"})]})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{htmlFor:"subject",children:["제목 ",e.jsx("span",{className:"required",children:"*"})]}),e.jsx("input",{id:"subject",name:"subject",type:"text",required:!0,value:a.subject,onChange:s,placeholder:"문의 제목을 입력해주세요"})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{htmlFor:"content",children:["문의 내용 ",e.jsx("span",{className:"required",children:"*"})]}),e.jsx("textarea",{id:"content",name:"content",rows:6,required:!0,value:a.content,onChange:s,placeholder:"문의 내용을 자세히 작성해주세요."})]}),e.jsxs("label",{className:"privacy-agree",children:[e.jsx("input",{type:"checkbox",name:"agreePrivacy",checked:a.agreePrivacy,onChange:s}),e.jsxs("span",{children:["개인정보 수집·이용에 동의합니다. ",e.jsx("a",{href:"/privacy",target:"_blank",children:"[보기]"})]})]}),e.jsx("button",{type:"submit",className:"btn btn-primary btn-lg",style:{width:"100%"},disabled:o,children:o?"전송 중...":"문의 접수하기"})]})]})})]})}export{y as default}; diff --git a/backend/src/main/resources/static/assets/GuardiaDetail-5Pm8bk4O.js b/backend/src/main/resources/static/assets/GuardiaDetail-5Pm8bk4O.js new file mode 100644 index 00000000..ce2332d1 --- /dev/null +++ b/backend/src/main/resources/static/assets/GuardiaDetail-5Pm8bk4O.js @@ -0,0 +1 @@ +import{r as n,j as s,L as d}from"./index-ChpGil2q.js";const r=[{icon:"🤖",title:"AI 에이전트 자동화",desc:"Ollama 온프레미스 sLLM 기반. 메신저 한 줄 명령 → 자연어 파싱 → 자동 배포·운영. 외부 API 완전 차단으로 폐쇄망 환경 최적화."},{icon:"🔧",title:"에이전트리스 아키텍처",desc:"대상 서버에 어떤 소프트웨어도 설치하지 않습니다. 표준 SSH/SFTP 프로토콜만으로 레거시 WAS(Tomcat/JBoss/WebLogic)를 원격 관리."},{icon:"💬",title:"ChatOps 메신저 통합",desc:"카카오워크, 네이버웍스, 슬랙 등 익숙한 메신저에서 /deploy, /status, /incident 명령으로 인프라를 즉시 제어."},{icon:"📊",title:"통합 ITSM 대시보드",desc:"SR·인시던트·변경관리·SLA·CMDB·예측 유지보수를 단일 플랫폼에서 관리. 7일 추이 차트와 AI 인사이트 실시간 제공."},{icon:"🔒",title:"엔터프라이즈 보안",desc:"AES-256-GCM 암호화, MFA/OTP, PAM 특권접근관리, SHA-256 해시체인 불변 감사로그, Zero Trust 지속 인증."},{icon:"🏗️",title:"PMS 프로젝트 관리",desc:"WBS·산출물·일간/주간/월간 자동 보고서(Excel·PDF·PPT). 이슈·위험 관리, Gitea 연동, Jenkins CI/CD 파이프라인."},{icon:"🌐",title:"공공기관 필수 준수",desc:"행안부 SW 보안약점 자동 점검, KWCAG 2.1 웹접근성, 개인정보보호법 준수 스캔. 19개 공공기관 체크리스트 내장."},{icon:"📡",title:"Scouter APM 모니터링",desc:"Java WAS(Tomcat/JBoss) 전문 APM. CPU·Heap·TPS·응답시간 실시간 수집, 이상 탐지 시 자동 인시던트 생성."}],o=[{name:"COMMUNITY",badge:"무료",color:"#10B981",target:"소규모 기관·검토용",features:["기본 SR 관리 (무제한)","CMDB 서버 20대","사용자 10명","대시보드","봇 기본 명령어"],cta:"무료 시작",href:"/support/contact?type=community"},{name:"STANDARD",badge:"권장",color:"var(--primary)",target:"중형 기관",features:["전체 ITSM 기능","AI 에이전트 자동화","LDAP/AD 연동","MFA 보안","SLA 관리","PMS 기본"],cta:"도입 문의",href:"/support/contact?type=standard",highlight:!0},{name:"ENTERPRISE",badge:"맞춤",color:"#6366F1",target:"대형 관공서·광역기관",features:["무제한 서버·기관","취약점 자동 스캔","Scouter APM","FinOps 비용 분석","SIEM 연동","전담 기술 지원"],cta:"전문가 상담",href:"/support/contact?type=enterprise"}],m=[{cmd:"/sr <제목>",desc:"SR(서비스요청) 즉시 접수",cat:"SR 관리"},{cmd:"/status",desc:"시스템 전체 현황 요약",cat:"SR 관리"},{cmd:"/assign <담당자>",desc:"SR 담당자 즉시 배정",cat:"SR 관리"},{cmd:"/approve ",desc:"SR 즉시 승인",cat:"SR 관리"},{cmd:"/sla",desc:"SLA 위반 현황 목록",cat:"SR 관리"},{cmd:"/incident <제목> [P1~P4]",desc:"인시던트 빠른 등록",cat:"인시던트"},{cmd:"/oncall",desc:"현재 당직자 즉시 조회",cat:"인시던트"},{cmd:"/rca ",desc:"AI 자동 RCA 근본원인 분석",cat:"인시던트"},{cmd:"/escalate ",desc:"당직자에게 에스컬레이션",cat:"인시던트"},{cmd:"!deploy <세션ID>",desc:"WAS 배포 실행 (SSH)",cat:"배포 제어"},{cmd:"/rollback <세션ID>",desc:"긴급 롤백",cat:"배포 제어"},{cmd:"!health <서버명>",desc:"서버 헬스체크",cat:"배포 제어"},{cmd:"/pms <프로젝트코드>",desc:"프로젝트 진척 현황",cat:"PMS"},{cmd:"/report <코드> weekly",desc:"주간 보고서 메신저 발송",cat:"PMS"},{cmd:"/wbs <코드>",desc:"WBS 지연 현황",cat:"PMS"},{cmd:"/scouter <서버명>",desc:"Scouter APM 실시간 메트릭",cat:"모니터링"},{cmd:"/scan",desc:"시큐어코딩·보안 자동 점검",cat:"보안"},{cmd:"/vuln <서버|IP>",desc:"취약점 스캔",cat:"보안"},{cmd:"/notify <메시지>",desc:"운영팀 전체 공지 발송",cat:"공지"}],h=[{name:"카카오워크",icon:"💬",color:"#FAE100",textColor:"#3C1E1E",desc:"결재 버튼 + 봇 명령 완벽 지원"},{name:"네이버웍스",icon:"🟢",color:"#03C75A",textColor:"#fff",desc:"Flex 메시지 + Rich 결과 표시"},{name:"슬랙",icon:"💜",color:"#611F69",textColor:"#fff",desc:"슬래시 명령 + 블록킷 UI"},{name:"자체 메신저",icon:"🔵",color:"#0051A2",textColor:"#fff",desc:"GUARDiA 내장 Slack형 메신저"}],x=[{category:"Backend",items:["Python 3.11 / FastAPI","SQLAlchemy Async","PostgreSQL / SQLite"]},{category:"AI·LLM",items:["Ollama (온프레미스)","llama3.1:8b / codellama","외부 API 완전 차단"]},{category:"Infra",items:["paramiko SSH/SFTP","에이전트리스","AES-256-GCM 암호화"]},{category:"Frontend",items:["React.js / PWA","Chart.js 대시보드","D3.js 토폴로지"]},{category:"DevOps",items:["Jenkins CI/CD","Gitea 형상관리","Docker / K8s"]},{category:"모니터링",items:["Scouter APM","Prometheus/Grafana","ELK/Splunk SIEM"]}];function N(){const[i,t]=n.useState("features");return s.jsxs("main",{id:"main-content",className:"guardia-page",children:[s.jsxs("section",{className:"gd-hero",children:[s.jsx("div",{className:"gd-hero-overlay"}),s.jsxs("div",{className:"container gd-hero-inner",children:[s.jsxs("div",{className:"gd-hero-text",children:[s.jsx("span",{className:"badge badge-new",style:{fontSize:"12px",padding:"4px 12px"},children:"NEW v2.0"}),s.jsxs("h1",{className:"gd-hero-title",children:[s.jsx("span",{children:"GUARDiA"})," ITSM"]}),s.jsxs("p",{className:"gd-hero-sub",children:["AI 기반 레거시 인프라 자율 운영 플랫폼",s.jsx("br",{}),s.jsx("strong",{children:"메신저 한 줄 명령"}),"으로 1,000개 관공서 인프라를 자동화"]}),s.jsxs("div",{className:"gd-hero-actions",children:[s.jsx(d,{to:"/support/contact?type=demo",className:"btn btn-white btn-lg",children:"무료 데모 신청"}),s.jsx("a",{href:"#features",className:"btn btn-lg",style:{color:"rgba(255,255,255,.85)",border:"1px solid rgba(255,255,255,.3)"},children:"기능 살펴보기 ↓"})]})]}),s.jsx("div",{className:"gd-hero-stats",children:[{val:"1,000+",lab:"관리 기관"},{val:"99.9%",lab:"가용성"},{val:"70%",lab:"운영 비용 절감"},{val:"0개",lab:"대상 서버 추가 설치"}].map((e,c)=>s.jsxs("div",{className:"gd-stat",children:[s.jsx("div",{className:"gd-stat-val",children:e.val}),s.jsx("div",{className:"gd-stat-lab",children:e.lab})]},c))})]})]}),s.jsx("div",{className:"gd-tabs-bar",children:s.jsx("div",{className:"container",children:s.jsx("div",{className:"gd-tabs",children:[{id:"features",label:"핵심 기능"},{id:"messenger",label:"Messenger Bot"},{id:"editions",label:"에디션 비교"},{id:"tech",label:"기술 스택"},{id:"usecase",label:"도입 사례"}].map(e=>s.jsx("button",{className:`gd-tab ${i===e.id?"active":""}`,onClick:()=>t(e.id),children:e.label},e.id))})})}),i==="features"&&s.jsx("section",{id:"features",className:"section",children:s.jsxs("div",{className:"container",children:[s.jsxs("div",{className:"section-header",children:[s.jsx("span",{className:"section-label",children:"Core Features"}),s.jsxs("h2",{className:"section-title",children:["GUARDiA가 제공하는",s.jsx("br",{}),s.jsx("em",{children:"8가지 핵심 기능"})]}),s.jsx("div",{className:"divider"})]}),s.jsx("div",{className:"gd-screenshots",children:[{file:"01_dashboard",caption:"통합 대시보드 — SR·SLA·AI 인사이트"},{file:"02_sr_list",caption:"SR 서비스 요청 — 칸반/목록 뷰"},{file:"03_si_project",caption:"PMS 프로젝트 — WBS·산출물·보고서"},{file:"04_incidents",caption:"인시던트 관리 — AI 자동 RCA"},{file:"05_agents",caption:"AI 에이전트 — Ollama 온프레미스"},{file:"06_license",caption:"라이선스 관리 — 에디션·체험판"}].map((e,c)=>s.jsxs("div",{className:"screenshot-card",children:[s.jsx("img",{src:`/screenshots/${e.file}.png`,alt:e.caption,className:"screenshot-img",onError:a=>{a.target.style.display="none",a.target.nextSibling.style.display="flex"}}),s.jsxs("div",{className:"screenshot-placeholder",style:{display:"none"},children:[s.jsx("span",{className:"icon",children:"🖥️"}),s.jsx("span",{children:"준비 중"})]}),s.jsx("div",{className:"screenshot-caption",children:e.caption})]},c))}),s.jsx("div",{className:"section-header",style:{marginTop:"60px",marginBottom:"32px"},children:s.jsx("h3",{style:{fontSize:"28px",fontWeight:"800",color:"var(--gray-900)"},children:"핵심 기능 상세"})}),s.jsx("div",{className:"gd-features-grid",children:r.map((e,c)=>s.jsxs("div",{className:"gd-feature-card card",children:[s.jsx("div",{className:"gd-feature-icon",children:e.icon}),s.jsx("h3",{children:e.title}),s.jsx("p",{children:e.desc})]},c))})]})}),i==="messenger"&&s.jsx("section",{className:"section",children:s.jsxs("div",{className:"container",children:[s.jsxs("div",{className:"section-header",children:[s.jsx("span",{className:"section-label",children:"ChatOps Messenger"}),s.jsxs("h2",{className:"section-title",children:["메신저 하나로",s.jsx("br",{}),s.jsx("em",{children:"모든 인프라를 제어"})]}),s.jsx("div",{className:"divider"}),s.jsxs("p",{className:"section-desc",children:["익숙한 메신저에서 명령어 하나로 서버 배포·장애 대응·보고서 발송까지.",s.jsx("br",{}),"GUARDiA Bot은 25개 명령어로 IT 운영의 모든 순간을 지원합니다."]})]}),s.jsx("div",{className:"messenger-platforms",children:h.map((e,c)=>s.jsxs("div",{className:"messenger-platform",style:{background:e.color},children:[s.jsx("span",{className:"platform-icon",children:e.icon}),s.jsxs("div",{children:[s.jsx("strong",{style:{color:e.textColor},children:e.name}),s.jsx("p",{style:{color:e.textColor,opacity:.85},children:e.desc})]})]},c))}),s.jsxs("div",{className:"cmd-catalog",children:[s.jsx("h3",{className:"cmd-catalog-title",children:"25개 봇 명령어 전체 목록"}),["SR 관리","인시던트","배포 제어","PMS","모니터링","보안","공지"].map(e=>{const c=m.filter(a=>a.cat===e);return s.jsxs("div",{className:"cmd-group",children:[s.jsx("h4",{className:"cmd-group-title",children:e}),s.jsx("div",{className:"cmd-list",children:c.map((a,l)=>s.jsxs("div",{className:"cmd-item",children:[s.jsx("code",{className:"cmd-code",children:a.cmd}),s.jsx("span",{className:"cmd-desc",children:a.desc})]},l))})]},e)})]}),s.jsxs("div",{className:"messenger-demo",children:[s.jsx("h3",{className:"demo-title",children:"실제 운영 시나리오"}),s.jsxs("div",{className:"demo-scenario",children:[s.jsxs("div",{className:"demo-step",children:[s.jsx("div",{className:"step-num",children:"1"}),s.jsxs("div",{className:"step-content",children:[s.jsx("strong",{children:"장애 탐지"}),s.jsx("p",{children:"Scouter APM이 서버 CPU 90% 감지 → 자동으로 GUARDiA 운영 채널에 경보 발송"}),s.jsx("div",{className:"chat-bubble bot",children:"🚨 web-01 CPU 90.3% — P2 인시던트 자동 등록: INC-20260530-A1B2C3"})]})]}),s.jsxs("div",{className:"demo-step",children:[s.jsx("div",{className:"step-num",children:"2"}),s.jsxs("div",{className:"step-content",children:[s.jsx("strong",{children:"담당자 즉시 대응"}),s.jsx("p",{children:"메신저에서 RCA 분석 요청"}),s.jsx("div",{className:"chat-bubble user",children:"/rca INC-20260530-A1B2C3"}),s.jsxs("div",{className:"chat-bubble bot",children:["🤖 AI RCA 분석 완료",s.jsx("br",{}),"근본원인: 메모리 누수 (Heap 98%)",s.jsx("br",{}),"재발방지: WAS 재기동 + 힙덤프 분석",s.jsx("br",{}),"신뢰도: 87%"]})]})]}),s.jsxs("div",{className:"demo-step",children:[s.jsx("div",{className:"step-num",children:"3"}),s.jsxs("div",{className:"step-content",children:[s.jsx("strong",{children:"원격 조치 실행"}),s.jsx("p",{children:"SSH 재기동 명령 실행"}),s.jsx("div",{className:"chat-bubble user",children:"!sm web-01 tomcat_restart"}),s.jsxs("div",{className:"chat-bubble bot",children:["✅ web-01 Tomcat 재기동 완료",s.jsx("br",{}),"소요: 38초 | CPU: 12% | 정상화"]})]})]}),s.jsxs("div",{className:"demo-step",children:[s.jsx("div",{className:"step-num",children:"4"}),s.jsxs("div",{className:"step-content",children:[s.jsx("strong",{children:"자동 보고"}),s.jsx("p",{children:"인시던트 처리 결과 자동 보고서 발송"}),s.jsx("div",{className:"chat-bubble user",children:"/notify 22:15 web-01 서버 장애 복구 완료. 원인: 메모리 누수 재발 방지 조치 완료."}),s.jsx("div",{className:"chat-bubble bot",children:"✅ 운영팀 전체 공지 발송 완료 (ops 채널)"})]})]})]})]})]})}),i==="editions"&&s.jsx("section",{className:"section",children:s.jsxs("div",{className:"container",children:[s.jsxs("div",{className:"section-header",children:[s.jsx("span",{className:"section-label",children:"Editions"}),s.jsxs("h2",{className:"section-title",children:["기관 규모에 맞는",s.jsx("br",{}),s.jsx("em",{children:"에디션 선택"})]}),s.jsx("div",{className:"divider"})]}),s.jsx("div",{className:"gd-editions-grid",children:o.map((e,c)=>s.jsxs("div",{className:`gd-edition-card ${e.highlight?"highlight":""}`,style:{"--ed-color":e.color},children:[e.highlight&&s.jsx("div",{className:"edition-recommend",children:"추천"}),s.jsxs("div",{className:"edition-header",children:[s.jsx("h3",{children:e.name}),s.jsx("span",{className:"edition-badge",children:e.badge})]}),s.jsx("p",{className:"edition-target",children:e.target}),s.jsx("ul",{className:"edition-features",children:e.features.map((a,l)=>s.jsxs("li",{children:[s.jsx("span",{className:"check",children:"✓"}),a]},l))}),s.jsx(d,{to:e.href,className:"btn edition-cta",children:e.cta})]},c))})]})}),i==="tech"&&s.jsx("section",{className:"section",children:s.jsxs("div",{className:"container",children:[s.jsxs("div",{className:"section-header",children:[s.jsx("span",{className:"section-label",children:"Technology"}),s.jsxs("h2",{className:"section-title",children:["검증된",s.jsx("br",{}),s.jsx("em",{children:"기술 스택"})]}),s.jsx("div",{className:"divider"}),s.jsx("p",{className:"section-desc",children:"온프레미스 전용 설계 — 외부 클라우드 의존 없는 완전 폐쇄망 동작"})]}),s.jsx("div",{className:"gd-tech-grid",children:x.map((e,c)=>s.jsxs("div",{className:"gd-tech-card card",children:[s.jsx("h3",{className:"tech-category",children:e.category}),s.jsx("ul",{className:"tech-items",children:e.items.map((a,l)=>s.jsx("li",{children:a},l))})]},c))})]})}),i==="usecase"&&s.jsx("section",{className:"section",children:s.jsxs("div",{className:"container",children:[s.jsxs("div",{className:"section-header",children:[s.jsx("span",{className:"section-label",children:"Use Cases"}),s.jsxs("h2",{className:"section-title",children:["실제 ",s.jsx("em",{children:"도입 사례"})]}),s.jsx("div",{className:"divider"})]}),s.jsx("div",{className:"gd-usecases",children:[{org:"광역 지방자치단체",result:"레거시 서버 200대 SSH 자동화, 운영 인력 3명→1명",badge:"중앙부처"},{org:"공공기관 IT센터",result:"월간 SR 500건 처리, AI 자동분류로 80% 응답시간 단축",badge:"공공기관"},{org:"지방 교육청",result:"Tomcat 100대 무중단 배포 자동화, 장애 대응 시간 70% 단축",badge:"교육"}].map((e,c)=>s.jsxs("div",{className:"usecase-card card",children:[s.jsx("span",{className:"badge badge-primary",children:e.badge}),s.jsx("h3",{children:e.org}),s.jsx("p",{children:e.result})]},c))})]})}),s.jsx("section",{className:"gd-cta",children:s.jsxs("div",{className:"container",children:[s.jsx("h2",{children:"지금 바로 무료 데모를 경험해 보세요"}),s.jsx("p",{children:"전문 컨설턴트가 귀 기관 환경에 맞는 최적의 구성을 제안해 드립니다."}),s.jsxs("div",{className:"gd-cta-actions",children:[s.jsx(d,{to:"/support/contact?type=demo",className:"btn btn-white btn-lg",children:"무료 데모 신청"}),s.jsx(d,{to:"/support/catalog",className:"btn btn-lg",style:{color:"rgba(255,255,255,.8)",border:"1px solid rgba(255,255,255,.3)"},children:"제품 소개서"})]})]})})]})}export{N as default}; diff --git a/backend/src/main/resources/static/assets/GuardiaDetail-Ax0ubrjA.css b/backend/src/main/resources/static/assets/GuardiaDetail-Ax0ubrjA.css new file mode 100644 index 00000000..9cd92fa4 --- /dev/null +++ b/backend/src/main/resources/static/assets/GuardiaDetail-Ax0ubrjA.css @@ -0,0 +1 @@ +.guardia-page{padding-top:var(--header-h)}.gd-hero{position:relative;background:linear-gradient(135deg,#0a0f24,#001f5c,#0051a2);padding:80px 0 60px;overflow:hidden}.gd-hero:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background:radial-gradient(ellipse at 70% 50%,rgba(0,163,224,.15) 0%,transparent 70%)}.gd-hero-overlay{position:absolute;top:0;right:0;bottom:0;left:0;background:#0003}.gd-hero-inner{position:relative;z-index:2;display:grid;grid-template-columns:1fr auto;gap:60px;align-items:center}.gd-hero-title{font-size:clamp(40px,5vw,64px);font-weight:900;color:#fff;margin:12px 0 16px}.gd-hero-title span{color:var(--accent)}.gd-hero-sub{font-size:18px;color:#fffc;line-height:1.7;margin-bottom:32px}.gd-hero-sub strong{color:#fff}.gd-hero-actions{display:flex;gap:16px;flex-wrap:wrap}.gd-hero-stats{display:grid;grid-template-columns:repeat(2,1fr);gap:16px;flex-shrink:0}.gd-stat{background:#ffffff14;border:1px solid rgba(255,255,255,.15);border-radius:var(--radius);padding:20px 24px;text-align:center}.gd-stat-val{font-size:28px;font-weight:900;color:var(--accent)}.gd-stat-lab{font-size:12px;color:#ffffffb3;margin-top:4px}.gd-tabs-bar{background:var(--white);border-bottom:2px solid var(--gray-200);position:sticky;top:var(--header-h);z-index:100}.gd-tabs{display:flex;gap:0;overflow-x:auto}.gd-tab{padding:16px 24px;font-size:14px;font-weight:600;color:var(--gray-600);border-bottom:3px solid transparent;margin-bottom:-2px;white-space:nowrap;transition:all var(--fast)}.gd-tab:hover{color:var(--primary)}.gd-tab.active{color:var(--primary);border-bottom-color:var(--primary)}.gd-features-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}.gd-feature-card{padding:28px;display:flex;flex-direction:column;gap:12px}.gd-feature-icon{font-size:36px}.gd-feature-card h3{font-size:16px;font-weight:700;color:var(--gray-900)}.gd-feature-card p{font-size:14px;color:var(--gray-600);line-height:1.7}.gd-screenshots{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:40px}.screenshot-card{border-radius:var(--radius);overflow:hidden;box-shadow:var(--shadow);border:1px solid var(--gray-200);transition:all var(--mid) var(--ease)}.screenshot-card:hover{transform:translateY(-4px);box-shadow:var(--shadow-lg)}.screenshot-img{width:100%;aspect-ratio:16/9;object-fit:cover;display:block}.screenshot-placeholder{width:100%;aspect-ratio:16/9;background:linear-gradient(135deg,#1e2333,#2d3748);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;color:var(--gray-400);font-size:13px}.screenshot-placeholder .icon{font-size:32px}.screenshot-caption{padding:12px 16px;font-size:13px;font-weight:600;color:var(--gray-700);background:var(--white)}.messenger-platforms{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:48px}.messenger-platform{border-radius:var(--radius);padding:20px;display:flex;align-items:center;gap:14px}.platform-icon{font-size:28px;flex-shrink:0}.messenger-platform strong{display:block;font-size:15px;font-weight:700}.messenger-platform p{font-size:12px;margin-top:2px}.cmd-catalog{background:var(--gray-900);border-radius:var(--radius-lg);padding:32px;margin-bottom:48px}.cmd-catalog-title{color:#fff;font-size:18px;font-weight:700;margin-bottom:24px;padding-bottom:12px;border-bottom:1px solid rgba(255,255,255,.1)}.cmd-group{margin-bottom:20px}.cmd-group-title{font-size:11px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;color:var(--accent);margin-bottom:10px}.cmd-list{display:flex;flex-direction:column;gap:6px}.cmd-item{display:flex;align-items:baseline;gap:16px}.cmd-code{font-family:Courier New,monospace;font-size:13px;color:#a5f3fc;background:#a5f3fc14;padding:3px 8px;border-radius:4px;white-space:nowrap;flex-shrink:0;min-width:220px}.cmd-desc{font-size:13px;color:#ffffffa6}.demo-title{font-size:22px;font-weight:700;color:var(--gray-900);margin-bottom:24px}.demo-scenario{display:flex;flex-direction:column;gap:32px}.demo-step{display:flex;gap:20px}.step-num{width:40px;height:40px;flex-shrink:0;background:var(--primary);color:#fff;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:700}.step-content{flex:1}.step-content strong{font-size:16px;color:var(--gray-900);display:block;margin-bottom:6px}.step-content>p{font-size:14px;color:var(--gray-600);margin-bottom:10px}.chat-bubble{padding:12px 16px;border-radius:12px;font-size:13px;line-height:1.6;margin-top:6px;max-width:520px}.chat-bubble.bot{background:#1e2333;color:#ffffffe6}.chat-bubble.user{background:var(--primary-light);color:var(--primary);font-weight:600}.gd-editions-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}.gd-edition-card{border:2px solid var(--gray-200);border-radius:var(--radius-lg);padding:36px 28px;position:relative;display:flex;flex-direction:column;gap:16px;transition:all var(--mid) var(--ease)}.gd-edition-card:hover{box-shadow:var(--shadow-lg)}.gd-edition-card.highlight{border-color:var(--primary);box-shadow:0 0 0 4px #0051a21a}.edition-recommend{position:absolute;top:-12px;left:50%;transform:translate(-50%);background:var(--primary);color:#fff;font-size:12px;font-weight:700;padding:3px 14px;border-radius:20px}.edition-header{display:flex;align-items:center;justify-content:space-between}.edition-header h3{font-size:22px;font-weight:900;color:var(--ed-color, var(--gray-900))}.edition-badge{background:color-mix(in srgb,var(--ed-color, var(--primary)) 15%,transparent);color:var(--ed-color, var(--primary));padding:3px 10px;border-radius:12px;font-size:12px;font-weight:700}.edition-target{font-size:13px;color:var(--gray-500)}.edition-features{display:flex;flex-direction:column;gap:10px;flex:1}.edition-features li{display:flex;align-items:flex-start;gap:10px;font-size:14px;color:var(--gray-700)}.check{color:var(--ed-color, var(--primary));font-weight:700;flex-shrink:0}.edition-cta{background:var(--ed-color, var(--primary));color:#fff;text-align:center;padding:12px;border-radius:var(--radius);font-weight:600;width:100%;justify-content:center}.gd-tech-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}.gd-tech-card{padding:28px}.tech-category{font-size:16px;font-weight:700;color:var(--primary);margin-bottom:16px}.tech-items{display:flex;flex-direction:column;gap:10px}.tech-items li{font-size:14px;color:var(--gray-700);padding:8px 12px;background:var(--gray-50);border-radius:var(--radius-sm);border-left:3px solid var(--accent)}.gd-usecases{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}.usecase-card{padding:28px;display:flex;flex-direction:column;gap:12px}.usecase-card h3{font-size:17px;font-weight:700;color:var(--gray-900)}.usecase-card p{font-size:14px;color:var(--gray-600);line-height:1.7}.gd-cta{background:linear-gradient(135deg,var(--primary-dark),#0a0f24);padding:80px 0;text-align:center}.gd-cta h2{font-size:32px;font-weight:800;color:#fff;margin-bottom:12px}.gd-cta p{font-size:17px;color:#ffffffbf;margin-bottom:32px}.gd-cta-actions{display:flex;gap:16px;justify-content:center;flex-wrap:wrap}@media (max-width: 1024px){.gd-hero-inner{grid-template-columns:1fr}.gd-hero-stats{grid-template-columns:repeat(4,1fr)}.gd-features-grid,.gd-screenshots,.messenger-platforms{grid-template-columns:repeat(2,1fr)}.gd-editions-grid{grid-template-columns:1fr}.gd-tech-grid{grid-template-columns:repeat(2,1fr)}.gd-usecases{grid-template-columns:1fr}}@media (max-width: 768px){.gd-features-grid,.gd-screenshots,.messenger-platforms{grid-template-columns:1fr}.gd-hero-stats{grid-template-columns:repeat(2,1fr)}.gd-tech-grid{grid-template-columns:1fr}.cmd-item{flex-direction:column;gap:4px}.cmd-code{min-width:unset}} diff --git a/backend/src/main/resources/static/assets/Home-BC38QtTl.js b/backend/src/main/resources/static/assets/Home-BC38QtTl.js new file mode 100644 index 00000000..a1a23fc3 --- /dev/null +++ b/backend/src/main/resources/static/assets/Home-BC38QtTl.js @@ -0,0 +1,6 @@ +import{r as i,j as s,R as u,L as l}from"./index-ChpGil2q.js";import{a as p}from"./index-DcNlVx-A.js";const n=[{title:`AI 기반 인프라 +자율 운영 플랫폼`,sub:"GUARDiA ITSM — 메신저 한 줄로 1,000개 관공서 인프라를 자동화",cta:{label:"GUARDiA 알아보기",path:"/solution/guardia"},badge:"NEW",bg:"slide-1"},{title:`공공기관 전문 +IT 솔루션 기업`,sub:"20년 경험의 지오정보기술이 최첨단 AI 기술로 여러분과 함께합니다",cta:{label:"회사소개 보기",path:"/company/greeting"},badge:"",bg:"slide-2"},{title:`에이전트리스 +자동화 혁신`,sub:"대상 서버에 소프트웨어 설치 없이 SSH만으로 레거시 인프라를 관리",cta:{label:"도입 문의",path:"/support/contact"},badge:"",bg:"slide-3"}],b=[{icon:"🤖",title:"AI 자동화",desc:"GUARDiA ITSM 플랫폼으로 레거시 인프라 운영을 완전 자동화",path:"/solution/guardia",color:"var(--primary)"},{icon:"🏗️",title:"SI 구축",desc:"공공기관 정보화사업 시스템 통합 및 맞춤형 개발",path:"/business/reference",color:"var(--accent)"},{icon:"💼",title:"ERP·CRM·BI",desc:"기업 경영 효율화를 위한 통합 솔루션 패키지",path:"/solution/erp",color:"#10B981"}],v=[{icon:"💬",label:"ChatOps",desc:"메신저 명령으로 인프라 제어"},{icon:"🔧",label:"에이전트리스",desc:"SSH만으로 에이전트 설치 없음"},{icon:"📊",label:"통합 ITSM",desc:"SR·인시던트·변경·SLA 통합"},{icon:"🔒",label:"엔터프라이즈 보안",desc:"MFA·PAM·Zero Trust"}],g=[{value:"1,000+",label:"관리 가능 기관 수"},{value:"99.9%",label:"시스템 가용성"},{value:"70%",label:"SR 처리 시간 단축"},{value:"20년+",label:"IT 사업 경험"}];function w(){const[d,t]=i.useState(0),[r,o]=i.useState(!1),[h,x]=i.useState([]),m=i.useRef(null);i.useEffect(()=>{if(!r)return m.current=setInterval(()=>t(e=>(e+1)%n.length),5e3),()=>clearInterval(m.current)},[r]),i.useEffect(()=>{p.get("/api/news?size=4").then(e=>x(e.data.content||[])).catch(()=>{})},[]);const j=()=>t(e=>(e-1+n.length)%n.length),N=()=>t(e=>(e+1)%n.length),c=n[d];return s.jsxs("main",{id:"main-content",children:[s.jsxs("section",{className:`hero hero-${d}`,onMouseEnter:()=>o(!0),onMouseLeave:()=>o(!1),"aria-label":"메인 슬라이더",children:[s.jsx("div",{className:"hero-overlay"}),s.jsxs("div",{className:"hero-content container",children:[c.badge&&s.jsx("span",{className:"hero-badge",children:c.badge}),s.jsx("h1",{className:"hero-title",children:c.title.split(` +`).map((e,a)=>s.jsxs(u.Fragment,{children:[e,as.jsx("button",{className:`hero-dot ${a===d?"active":""}`,onClick:()=>t(a),"aria-label":`슬라이드 ${a+1}`},a))}),s.jsx("button",{onClick:N,"aria-label":"다음 슬라이드",className:"hero-arrow",children:"›"}),s.jsx("button",{onClick:()=>o(e=>!e),className:"hero-pause","aria-label":r?"재생":"일시정지",children:r?"▶":"⏸"})]}),s.jsxs("div",{className:"hero-scroll-hint","aria-hidden":"true",children:[s.jsx("span",{children:"SCROLL"}),s.jsx("div",{className:"scroll-line"})]})]}),s.jsx("section",{className:"section section-business",children:s.jsxs("div",{className:"container",children:[s.jsxs("div",{className:"section-header",children:[s.jsx("span",{className:"section-label",children:"Our Business"}),s.jsxs("h2",{className:"section-title",children:["기업과 기관을 위한",s.jsx("br",{}),s.jsx("em",{children:"맞춤형 IT 솔루션"})]}),s.jsx("div",{className:"divider"})]}),s.jsx("div",{className:"business-grid",children:b.map((e,a)=>s.jsxs(l,{to:e.path,className:"business-card",children:[s.jsx("div",{className:"business-icon",style:{background:e.color+"18",color:e.color},children:e.icon}),s.jsx("h3",{className:"business-title",children:e.title}),s.jsx("p",{className:"business-desc",children:e.desc}),s.jsx("span",{className:"business-more",style:{color:e.color},children:"자세히 보기 →"})]},a))})]})}),s.jsx("section",{className:"section section-guardia",children:s.jsx("div",{className:"container",children:s.jsxs("div",{className:"guardia-inner",children:[s.jsxs("div",{className:"guardia-text",children:[s.jsx("span",{className:"section-label",children:"대표 솔루션"}),s.jsxs("h2",{className:"section-title",style:{textAlign:"left"},children:[s.jsx("em",{children:"GUARDiA ITSM"}),s.jsx("br",{}),"AI 기반 인프라 자율 운영"]}),s.jsx("div",{className:"divider divider-left"}),s.jsx("p",{className:"guardia-desc",children:"1,000개 이상의 관공서 레거시 인프라를 메신저 한 줄 명령으로 제어하는 온프레미스 AI ChatOps 플랫폼. 에이전트 설치 없이 SSH/SFTP만으로 배포·운영을 완전 자동화합니다."}),s.jsx("div",{className:"guardia-features",children:v.map((e,a)=>s.jsxs("div",{className:"guardia-feature",children:[s.jsx("span",{className:"feature-icon",children:e.icon}),s.jsxs("div",{children:[s.jsx("strong",{children:e.label}),s.jsx("p",{children:e.desc})]})]},a))}),s.jsxs("div",{className:"guardia-actions",children:[s.jsx(l,{to:"/solution/guardia",className:"btn btn-primary",children:"GUARDiA 상세보기"}),s.jsx(l,{to:"/support/contact",className:"btn btn-outline",children:"도입 문의"})]})]}),s.jsx("div",{className:"guardia-visual",children:s.jsxs("div",{className:"guardia-mockup",children:[s.jsxs("div",{className:"mockup-bar",children:[s.jsx("span",{}),s.jsx("span",{}),s.jsx("span",{})]}),s.jsx("div",{className:"mockup-content",children:s.jsxs("div",{className:"mockup-chat",children:[s.jsxs("div",{className:"chat-msg bot",children:[s.jsx("span",{className:"chat-name",children:"GUARDiA Bot"}),s.jsx("p",{children:"안녕하세요! 무엇을 도와드릴까요?"})]}),s.jsx("div",{className:"chat-msg user",children:s.jsx("p",{children:"/deploy web-server-01"})}),s.jsx("div",{className:"chat-msg bot",children:s.jsxs("p",{children:["✅ web-server-01 배포 완료",s.jsx("br",{}),"헬스체크: 정상 | 소요: 42초"]})}),s.jsx("div",{className:"chat-msg user",children:s.jsx("p",{children:"/status"})}),s.jsx("div",{className:"chat-msg bot",children:s.jsxs("p",{children:["📊 시스템 현황",s.jsx("br",{}),"SR 처리중: 3건 | SLA 준수율: 98.2%",s.jsx("br",{}),"서버 이상: 0건 ✅"]})})]})})]})})]})})}),s.jsx("section",{className:"section-kpi",children:s.jsx("div",{className:"container",children:s.jsx("div",{className:"kpi-grid",children:g.map((e,a)=>s.jsxs("div",{className:"kpi-item",children:[s.jsx("div",{className:"kpi-value",children:e.value}),s.jsx("div",{className:"kpi-label",children:e.label})]},a))})})}),s.jsx("section",{className:"section section-news",children:s.jsxs("div",{className:"container",children:[s.jsxs("div",{className:"section-header",children:[s.jsx("span",{className:"section-label",children:"Latest News"}),s.jsxs("h2",{className:"section-title",children:["지오정보기술 ",s.jsx("em",{children:"소식"})]}),s.jsx("div",{className:"divider"})]}),s.jsx("div",{className:"news-grid",children:h.length>0?h.map(e=>s.jsxs(l,{to:`/news/newsroom/${e.id}`,className:"news-card card",children:[s.jsxs("div",{className:"news-card-body",children:[s.jsx("span",{className:"badge badge-accent",children:e.category}),s.jsx("h3",{className:"news-title",children:e.title}),s.jsx("p",{className:"news-summary",children:e.summary})]}),s.jsxs("div",{className:"news-card-footer",children:[s.jsx("span",{className:"news-date",children:e.createdAt?new Date(e.createdAt).toLocaleDateString("ko-KR"):""}),s.jsx("span",{className:"news-more",children:"더보기 →"})]})]},e.id)):Array.from({length:4}).map((e,a)=>s.jsxs("div",{className:"news-card card skeleton",children:[s.jsx("div",{className:"skel-line",style:{width:"30%",height:"16px"}}),s.jsx("div",{className:"skel-line",style:{width:"90%",height:"20px",marginTop:"8px"}}),s.jsx("div",{className:"skel-line",style:{width:"70%",height:"14px",marginTop:"6px"}})]},a))}),s.jsx("div",{style:{textAlign:"center",marginTop:"40px"},children:s.jsx(l,{to:"/news/newsroom",className:"btn btn-outline",children:"모든 소식 보기"})})]})}),s.jsx("section",{className:"section-cta",children:s.jsx("div",{className:"container",children:s.jsxs("div",{className:"cta-inner",children:[s.jsxs("div",{className:"cta-text",children:[s.jsx("h2",{children:"GUARDiA ITSM 도입을 검토하고 계신가요?"}),s.jsx("p",{children:"전문 컨설턴트가 귀 기관 환경에 맞는 최적의 방안을 제안해 드립니다."})]}),s.jsxs("div",{className:"cta-actions",children:[s.jsx(l,{to:"/support/contact",className:"btn btn-white btn-lg",children:"무료 상담 신청"}),s.jsx(l,{to:"/solution/guardia",className:"btn btn-outline btn-lg",style:{color:"#fff",borderColor:"rgba(255,255,255,.5)"},children:"제품 소개서 다운로드"})]})]})})})]})}export{w as default}; diff --git a/backend/src/main/resources/static/assets/Home-jagO1aR4.css b/backend/src/main/resources/static/assets/Home-jagO1aR4.css new file mode 100644 index 00000000..9ede4896 --- /dev/null +++ b/backend/src/main/resources/static/assets/Home-jagO1aR4.css @@ -0,0 +1 @@ +.hero{position:relative;height:100vh;min-height:600px;display:flex;align-items:center;overflow:hidden;background:linear-gradient(135deg,#0a0f24,#0d2463,#0a1a4a);transition:background var(--slow)}.hero-0{background:linear-gradient(135deg,#0a0f24,#0d2463 60%,#0051a2)}.hero-1{background:linear-gradient(135deg,#1a0f3a,#2d1b69 60%,#0051a2)}.hero-2{background:linear-gradient(135deg,#001a3a,#003070 60%,#00a3e0)}.hero:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background:url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.03'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")}.hero-overlay{position:absolute;top:0;right:0;bottom:0;left:0;background:linear-gradient(to right,#00000080,#0000001a)}.hero-content{position:relative;z-index:2;max-width:700px}.hero-badge{display:inline-block;background:var(--accent);color:#fff;font-size:12px;font-weight:700;letter-spacing:2px;padding:4px 12px;border-radius:20px;margin-bottom:20px;animation:fadeUp .5s ease}.hero-title{font-size:clamp(36px,5.5vw,64px);font-weight:900;color:#fff;line-height:1.15;margin-bottom:20px;animation:fadeUp .5s .1s ease both}.hero-sub{font-size:clamp(16px,2vw,20px);color:#fffc;margin-bottom:40px;line-height:1.6;animation:fadeUp .5s .2s ease both}.hero-actions{display:flex;gap:16px;flex-wrap:wrap;animation:fadeUp .5s .3s ease both}.hero-btn-contact{border-color:#ffffff80;color:#fff!important}.hero-btn-contact:hover{background:#ffffff26!important;color:#fff!important}.hero-controls{position:absolute;bottom:40px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:12px;z-index:3}.hero-arrow{width:36px;height:36px;border-radius:50%;background:#ffffff26;color:#fff;font-size:20px;display:flex;align-items:center;justify-content:center;transition:background var(--fast)}.hero-arrow:hover{background:#ffffff4d}.hero-dots{display:flex;gap:8px}.hero-dot{width:8px;height:8px;border-radius:50%;background:#fff6;transition:all var(--mid)}.hero-dot.active{background:#fff;width:24px;border-radius:4px}.hero-pause{width:32px;height:32px;border-radius:50%;background:#ffffff1a;color:#ffffffb3;font-size:12px;display:flex;align-items:center;justify-content:center}.hero-scroll-hint{position:absolute;right:40px;bottom:40px;display:flex;flex-direction:column;align-items:center;gap:8px;color:#ffffff80;font-size:10px;letter-spacing:2px}.scroll-line{width:1px;height:60px;background:linear-gradient(to bottom,rgba(255,255,255,.5),transparent);animation:scrollPulse 1.5s ease infinite}@keyframes scrollPulse{0%,to{opacity:.5;transform:scaleY(1)}50%{opacity:1;transform:scaleY(1.1)}}.business-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:28px}.business-card{background:var(--white);border-radius:var(--radius-lg);padding:40px 32px;border:1px solid var(--gray-200);transition:all var(--mid) var(--ease);display:flex;flex-direction:column;gap:12px}.business-card:hover{box-shadow:var(--shadow-lg);transform:translateY(-6px);border-color:transparent}.business-icon{width:64px;height:64px;border-radius:var(--radius);font-size:28px;display:flex;align-items:center;justify-content:center}.business-title{font-size:22px;font-weight:700;color:var(--gray-900)}.business-desc{font-size:15px;color:var(--gray-600);line-height:1.7;flex:1}.business-more{font-size:14px;font-weight:600}.section-guardia{background:var(--gray-50)}.guardia-inner{display:grid;grid-template-columns:1fr 1fr;gap:80px;align-items:center}.guardia-desc{font-size:16px;color:var(--gray-600);line-height:1.8;margin:20px 0 28px}.guardia-features{display:flex;flex-direction:column;gap:16px;margin-bottom:32px}.guardia-feature{display:flex;align-items:flex-start;gap:16px;padding:14px 18px;background:var(--white);border-radius:var(--radius);border:1px solid var(--gray-200)}.feature-icon{font-size:24px;flex-shrink:0}.guardia-feature strong{display:block;font-size:15px;color:var(--gray-900)}.guardia-feature p{font-size:13px;color:var(--gray-600);margin-top:2px}.guardia-actions{display:flex;gap:12px;flex-wrap:wrap}.guardia-mockup{background:#1e1e2e;border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-lg);border:1px solid rgba(255,255,255,.1)}.mockup-bar{background:#2d2d3f;padding:10px 16px;display:flex;gap:6px}.mockup-bar span{width:12px;height:12px;border-radius:50%;background:#ff5f56}.mockup-bar span:nth-child(2){background:#ffbd2e}.mockup-bar span:nth-child(3){background:#27c93f}.mockup-content{padding:20px}.mockup-chat{display:flex;flex-direction:column;gap:12px}.chat-msg{max-width:80%}.chat-msg.bot{align-self:flex-start}.chat-msg.user{align-self:flex-end}.chat-name{font-size:11px;color:var(--accent);font-weight:700;display:block;margin-bottom:4px}.chat-msg p{padding:10px 14px;border-radius:12px;font-size:13px;line-height:1.5}.chat-msg.bot p{background:#2d2d3f;color:#ffffffe6}.chat-msg.user p{background:var(--primary);color:#fff}.section-kpi{background:var(--primary);padding:60px 0}.kpi-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:0}.kpi-item{text-align:center;padding:24px;border-right:1px solid rgba(255,255,255,.2)}.kpi-item:last-child{border-right:none}.kpi-value{font-size:clamp(32px,4vw,48px);font-weight:900;color:#fff}.kpi-label{font-size:14px;color:#ffffffbf;margin-top:6px}.news-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}.news-card{display:flex;flex-direction:column}.news-card-body{padding:24px;flex:1;display:flex;flex-direction:column;gap:10px}.news-title{font-size:16px;font-weight:700;color:var(--gray-900);line-height:1.4;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.news-summary{font-size:13px;color:var(--gray-600);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;flex:1}.news-card-footer{display:flex;justify-content:space-between;align-items:center;padding:12px 24px;border-top:1px solid var(--gray-100);font-size:12px}.news-date{color:var(--gray-400)}.news-more{color:var(--primary);font-weight:600}.skeleton{animation:pulse 1.5s ease infinite}@keyframes pulse{0%,to{opacity:.6}50%{opacity:1}}.skel-line{background:var(--gray-200);border-radius:4px}.section-cta{background:linear-gradient(135deg,var(--secondary),var(--primary-dark));padding:80px 0}.cta-inner{display:flex;align-items:center;justify-content:space-between;gap:40px;flex-wrap:wrap}.cta-text h2{font-size:28px;font-weight:800;color:#fff}.cta-text p{color:#ffffffbf;margin-top:8px;font-size:16px}.cta-actions{display:flex;gap:16px;flex-wrap:wrap;flex-shrink:0}@media (max-width: 1024px){.business-grid{grid-template-columns:repeat(2,1fr)}.guardia-inner{grid-template-columns:1fr;gap:40px}.kpi-grid,.news-grid{grid-template-columns:repeat(2,1fr)}}@media (max-width: 768px){.hero-title{font-size:32px}.hero-sub{font-size:15px}.hero-scroll-hint{display:none}.business-grid{grid-template-columns:1fr}.kpi-grid{grid-template-columns:repeat(2,1fr)}.news-grid{grid-template-columns:1fr}.cta-inner{flex-direction:column;text-align:center}.cta-actions{justify-content:center}} diff --git a/backend/src/main/resources/static/assets/NewsPage-BgXQ2CUT.css b/backend/src/main/resources/static/assets/NewsPage-BgXQ2CUT.css new file mode 100644 index 00000000..ad2129ba --- /dev/null +++ b/backend/src/main/resources/static/assets/NewsPage-BgXQ2CUT.css @@ -0,0 +1 @@ +.notice-back{font-size:14px;color:var(--primary);margin-bottom:24px;display:inline-flex;align-items:center;gap:4px;cursor:pointer;background:none;border:none}.news-cat-badge{display:inline-block;padding:4px 12px;border-radius:12px;font-size:12px;font-weight:700;margin-bottom:12px}.news-cat-badge.hot{background:#ef44441f;color:var(--danger)}.news-main{padding:40px;cursor:pointer;background:linear-gradient(135deg,var(--secondary),var(--primary-dark));border:none;margin-bottom:0}.news-main:hover{transform:none;box-shadow:var(--shadow-lg)}.news-main-title{font-size:26px;font-weight:900;color:#fff;margin-bottom:16px;line-height:1.35}.news-main-summary{font-size:15px;color:#ffffffb3;line-height:1.8;margin-bottom:16px;max-width:640px}.news-date{font-size:12px;color:#ffffff80}.news-card{padding:28px;cursor:pointer;display:flex;flex-direction:column}.news-card-title{font-size:15px;font-weight:700;color:var(--gray-900);margin-bottom:10px;line-height:1.5;flex:1}.news-card-summary{font-size:13px;color:var(--gray-600);line-height:1.7;margin-bottom:12px;flex:1}.news-date{font-size:12px;color:var(--gray-400)}.blog-card{padding:28px;display:flex;flex-direction:column}.blog-tag{display:inline-block;padding:4px 12px;border-radius:12px;font-size:12px;font-weight:700;margin-bottom:14px;align-self:flex-start}.blog-title{font-size:16px;font-weight:700;color:var(--gray-900);line-height:1.5;margin-bottom:12px}.blog-summary{font-size:13px;color:var(--gray-600);line-height:1.7;flex:1;margin-bottom:16px}.blog-meta{display:flex;gap:16px;font-size:12px;color:var(--gray-400);margin-bottom:16px}.blog-read-btn{padding:10px 20px;background:var(--primary-light);color:var(--primary);border-radius:8px;font-size:14px;font-weight:700;border:none;cursor:pointer;transition:all var(--fast);text-align:center}.blog-read-btn:hover{background:var(--primary);color:#fff} diff --git a/backend/src/main/resources/static/assets/NewsPage-mgytOZhS.js b/backend/src/main/resources/static/assets/NewsPage-mgytOZhS.js new file mode 100644 index 00000000..2f846974 --- /dev/null +++ b/backend/src/main/resources/static/assets/NewsPage-mgytOZhS.js @@ -0,0 +1,10 @@ +import{j as e,b as o,a as n,r as h,N as x}from"./index-ChpGil2q.js";/* empty css */const p=[{path:"/news/newsroom",label:"뉴스룸"},{path:"/news/blog",label:"기술 블로그"}];function d({title:a}){return e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"page-hero",children:e.jsxs("div",{className:"container",children:[e.jsx("span",{className:"section-label",children:"News"}),e.jsx("h1",{className:"page-hero-title",children:a})]})}),e.jsx("nav",{className:"sub-nav",children:e.jsx("div",{className:"container",children:p.map(t=>e.jsx(x,{to:t.path,className:({isActive:i})=>"sub-nav-item"+(i?" active":""),children:t.label},t.path))})})]})}const l=[{id:1,cat:"제품 출시",date:"2026.05.15",title:"GUARDiA ITSM v2.0 정식 출시 — AI ChatOps 오케스트레이션 플랫폼",summary:"메신저 한 줄 명령으로 1,000개+ 공공기관 레거시 인프라를 자동 운영하는 GUARDiA ITSM v2.0이 정식 출시되었습니다. 신규 기능으로 AI 자연어 명령, 에이전트리스 배포 엔진, 멀티테넌트 지원이 추가됐습니다.",content:`GUARDiA ITSM v2.0은 공공기관의 레거시 IT 인프라 운영 자동화를 위한 AI 기반 플랫폼입니다. + +주요 신기능: +- AI ChatOps: 메신저 자연어 명령 → Ollama LLM 파싱 → 자동 실행 +- 에이전트리스 배포: SSH/SFTP만으로 WAS 배포·롤백 자동화 +- 멀티테넌트: 1,000개+ 기관 동시 관리 +- GS인증 1등급 신청 완료 + +자세한 사항은 GUARDiA 소개 페이지를 참조해 주십시오.`,hot:!0},{id:2,cat:"수주 소식",date:"2026.04.20",title:"삼성전자 차세대 CRM 시스템 DB 마이그레이션 프로젝트 수주",summary:"(주)지오정보기술이 삼성전자 차세대 CRM 구축 프로젝트의 DB Migration/DA/튜닝을 담당합니다. EDB PostgreSQL 환경으로의 전환을 포함한 대규모 DB 현대화 작업을 수행합니다.",content:"삼성전자와의 두 번째 협력 프로젝트로, DB 마이그레이션 및 성능 튜닝을 담당합니다.",hot:!1},{id:3,cat:"기술 인증",date:"2026.03.10",title:"GUARDiA ITSM GS인증 1등급 신청 완료 — TTA 심사 예정",summary:"GUARDiA ITSM이 한국정보통신기술협회(TTA)에 GS인증 1등급을 신청하였습니다. 기능적합성, 신뢰성, 사용성, 보안성 등 ISO/IEC 25010 기준 8대 품질 특성 심사를 앞두고 있습니다.",content:"GS인증 심사는 2026년 9월 예정이며, 1등급 취득 시 조달청 나라장터 우선 등재가 가능합니다.",hot:!1},{id:4,cat:"수주 소식",date:"2026.02.15",title:"국민연금공단 차세대 시스템 구축 — AA 역할 수행",summary:"국민연금공단 차세대 시스템 구축 프로젝트에 Application Architect(AA)로 참여합니다. JSP/Java, Nexacro, Spring 기반의 대규모 공공기관 시스템 구축을 담당합니다.",content:"국민연금관리공단의 차세대 시스템은 수천만 가입자의 연금 관리 시스템으로, CI/CD 파이프라인 기반의 현대적인 개발 환경을 구축합니다.",hot:!1},{id:5,cat:"기업 소식",date:"2025.12.01",title:"2025년 사업실적 — 연간 프로젝트 10건 성공 수행",summary:"2025년 한 해 동안 삼성전자, 서울신용보증재단, 헌법재판소 등 10개 주요 프로젝트를 성공적으로 완료했습니다. 매출은 전년 대비 25% 성장하였습니다.",content:"창립 이래 최대 성과를 기록한 2025년 사업실적을 공유드립니다.",hot:!1},{id:6,cat:"파트너십",date:"2025.09.10",title:"Tibero 공식 파트너사 등록 — 공공기관 DB 전환 솔루션 강화",summary:"국산 DBMS Tibero의 공식 파트너사로 등록되었습니다. Oracle에서 Tibero로의 마이그레이션 및 공공기관 DB 현대화 사업을 공동으로 추진합니다.",content:"공공기관의 Oracle 라이선스 절감을 위한 Tibero 전환 프로젝트를 전문적으로 지원합니다.",hot:!1}];function c(){const[a,t]=h.useState(null),i=l.find(s=>s.id===a);return e.jsxs("main",{id:"main-content",className:"inner-page",children:[e.jsx(d,{title:"뉴스룸"}),e.jsx("section",{className:"section",children:e.jsx("div",{className:"container",children:i?e.jsxs("div",{style:{maxWidth:"760px",margin:"0 auto"},children:[e.jsx("button",{className:"notice-back",onClick:()=>t(null),children:"← 뉴스 목록"}),e.jsxs("div",{className:"news-detail card",style:{padding:"40px"},children:[e.jsx("span",{className:"news-cat-badge",style:{background:"var(--primary-light)",color:"var(--primary)"},children:i.cat}),e.jsx("h2",{style:{fontSize:"24px",fontWeight:"900",margin:"16px 0 8px",lineHeight:"1.4"},children:i.title}),e.jsx("p",{style:{fontSize:"13px",color:"var(--gray-400)",marginBottom:"32px"},children:i.date}),e.jsx("div",{className:"divider divider-left",style:{marginBottom:"32px"}}),i.content.split(` +`).map((s,m)=>s.trim()?e.jsx("p",{style:{fontSize:"15px",color:"var(--gray-700)",lineHeight:"1.85",marginBottom:"16px"},children:s},m):null)]})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"news-main card",onClick:()=>t(l[0].id),children:e.jsxs("div",{className:"news-main-content",children:[e.jsxs("span",{className:"news-cat-badge hot",children:["🔥 ",l[0].cat]}),e.jsx("h2",{className:"news-main-title",children:l[0].title}),e.jsx("p",{className:"news-main-summary",children:l[0].summary}),e.jsx("span",{className:"news-date",children:l[0].date})]})}),e.jsx("div",{className:"grid-3",style:{marginTop:"24px"},children:l.slice(1).map(s=>e.jsxs("div",{className:"card news-card",onClick:()=>t(s.id),children:[e.jsx("span",{className:"news-cat-badge",style:{background:"var(--primary-light)",color:"var(--primary)"},children:s.cat}),e.jsx("h3",{className:"news-card-title",children:s.title}),e.jsx("p",{className:"news-card-summary",children:s.summary}),e.jsx("span",{className:"news-date",children:s.date})]},s.id))})]})})})]})}const j=[{id:1,tag:"AI·LLM",date:"2026.05.20",title:"온프레미스 Ollama로 폐쇄망 ChatOps 구현하기",summary:"인터넷 없이 내부망에서 LLM을 운영하는 방법. Llama-3-8B 모델을 Ollama로 구동하고 FastAPI와 연동하는 전체 과정을 설명합니다.",readMin:12},{id:2,tag:"DevOps",date:"2026.05.10",title:"에이전트리스 WAS 배포 자동화 — paramiko SSH로 레거시 서버 관리",summary:"JEUS·Tomcat 등 레거시 WAS에 SSH/SFTP만으로 배포하는 방법. 백업→배포→헬스체크→롤백 파이프라인 구현 예제.",readMin:15},{id:3,tag:"보안",date:"2026.04.28",title:"AES-256-GCM으로 서버 자격증명을 안전하게 저장하는 법",summary:"공공기관 서버 SSH 비밀번호를 DB에 안전하게 암호화 저장하는 방법. IV·암호문·GCM Tag 구조 설계와 Python 구현.",readMin:8},{id:4,tag:"데이터베이스",date:"2026.04.15",title:"Oracle 19c → EDB PostgreSQL 마이그레이션 실전 가이드",summary:"삼성전자 CRM 프로젝트에서 실제 수행한 Oracle→EDB 마이그레이션 경험 공유. Smeta, ExemOne 활용 SQL 변환 전략.",readMin:20},{id:5,tag:"성능",date:"2026.03.25",title:"공공기관 행정정보시스템 SQL 튜닝 — 서울시립대 사례",summary:"대학행정정보시스템 성능 개선 프로젝트 실전 사례. JMeter 부하테스트와 Oracle 실행계획 분석으로 응답시간 60% 단축.",readMin:18},{id:6,tag:"아키텍처",date:"2026.03.10",title:"FastAPI 비동기 WebSocket으로 실시간 대시보드 구축하기",summary:"GUARDiA ITSM 실시간 모니터링 대시보드 구현 방법. FastAPI SSE + WebSocket + React를 조합한 풀스택 아키텍처.",readMin:14}],r={"AI·LLM":"#7c3aed",DevOps:"#0051A2",보안:"#dc2626",데이터베이스:"#d97706",성능:"#059669",아키텍처:"#0891b2"};function g(){return e.jsxs("main",{id:"main-content",className:"inner-page",children:[e.jsx(d,{title:"기술 블로그"}),e.jsx("section",{className:"section",children:e.jsxs("div",{className:"container",children:[e.jsxs("div",{className:"section-header",children:[e.jsx("span",{className:"section-label",children:"Tech Blog"}),e.jsx("h2",{className:"section-title",children:"기술 인사이트 공유"}),e.jsx("p",{className:"section-desc",children:"20년 이상의 프로젝트 경험에서 얻은 기술 노하우를 공유합니다"})]}),e.jsx("div",{className:"grid-3",children:j.map(a=>e.jsxs("div",{className:"card blog-card",children:[e.jsx("div",{className:"blog-tag",style:{background:r[a.tag]+"18",color:r[a.tag]},children:a.tag}),e.jsx("h3",{className:"blog-title",children:a.title}),e.jsx("p",{className:"blog-summary",children:a.summary}),e.jsxs("div",{className:"blog-meta",children:[e.jsxs("span",{children:["📅 ",a.date]}),e.jsxs("span",{children:["⏱ ",a.readMin,"분 읽기"]})]}),e.jsx("button",{className:"blog-read-btn",onClick:()=>alert("블로그 상세 페이지는 준비 중입니다."),children:"읽기 →"})]},a.id))})]})})]})}function u(){return e.jsxs(o,{children:[e.jsx(n,{path:"newsroom",element:e.jsx(c,{})}),e.jsx(n,{path:"blog",element:e.jsx(g,{})}),e.jsx(n,{path:"press",element:e.jsx(c,{})}),e.jsx(n,{path:"*",element:e.jsx(c,{})})]})}export{u as default}; diff --git a/backend/src/main/resources/static/assets/NotFound-KZZDVQMb.js b/backend/src/main/resources/static/assets/NotFound-KZZDVQMb.js new file mode 100644 index 00000000..b50468a2 --- /dev/null +++ b/backend/src/main/resources/static/assets/NotFound-KZZDVQMb.js @@ -0,0 +1 @@ +import{j as e,L as t}from"./index-ChpGil2q.js";function i(){return e.jsxs("main",{style:{paddingTop:"var(--header-h)",minHeight:"60vh",display:"flex",alignItems:"center",justifyContent:"center",flexDirection:"column",gap:"16px",textAlign:"center"},children:[e.jsx("div",{style:{fontSize:"72px"},children:"404"}),e.jsx("h1",{style:{fontSize:"24px",fontWeight:"700"},children:"페이지를 찾을 수 없습니다"}),e.jsx("p",{style:{color:"var(--gray-600)"},children:"요청하신 페이지가 존재하지 않거나 이동되었습니다."}),e.jsx(t,{to:"/",className:"btn btn-primary",children:"홈으로 돌아가기"})]})}export{i as default}; diff --git a/backend/src/main/resources/static/assets/Recruit-CbW65yqF.css b/backend/src/main/resources/static/assets/Recruit-CbW65yqF.css new file mode 100644 index 00000000..6c5d26ed --- /dev/null +++ b/backend/src/main/resources/static/assets/Recruit-CbW65yqF.css @@ -0,0 +1 @@ +.notice-back{font-size:14px;color:var(--primary);margin-bottom:24px;display:inline-flex;align-items:center;gap:4px;cursor:pointer;background:none;border:none}.job-card{padding:28px;display:flex;gap:24px;align-items:flex-start;cursor:pointer}.job-card:hover{border-color:var(--primary)}.job-info{flex:1}.job-title{font-size:18px;font-weight:700;color:var(--gray-900);margin-bottom:8px}.job-desc{font-size:13px;color:var(--gray-600);line-height:1.6;margin-bottom:12px}.job-stack{display:flex;gap:6px;flex-wrap:wrap}.job-tech{padding:4px 10px;background:var(--secondary);color:var(--accent);border-radius:4px;font-size:11px;font-weight:600}.job-meta{display:flex;flex-direction:column;gap:8px;align-items:flex-end;min-width:100px}.job-meta>div{display:flex;flex-direction:column;align-items:flex-end;font-size:13px;color:var(--gray-700)}.job-meta-label{font-size:11px;color:var(--gray-400);margin-bottom:2px}.welfare-cat{font-size:18px;font-weight:800;color:var(--gray-900);margin-bottom:20px}.welfare-card{padding:28px;text-align:center}.welfare-icon{font-size:36px;margin-bottom:12px}.welfare-name{font-size:15px;font-weight:700;margin-bottom:8px;color:var(--gray-900)}.welfare-desc{font-size:13px;color:var(--gray-600);line-height:1.6}.talent-wrap{background:var(--gray-50);border-radius:16px;padding:56px;margin-top:32px}.apply-form .form-group{margin-bottom:20px}.apply-form label{display:block;font-size:13px;font-weight:600;color:var(--gray-700);margin-bottom:6px}.apply-form input,.apply-form select,.apply-form textarea{width:100%;padding:12px 14px;border:1px solid var(--gray-200);border-radius:8px;font-size:14px;font-family:inherit;transition:border-color var(--fast)}.apply-form input:focus,.apply-form select:focus,.apply-form textarea:focus{outline:none;border-color:var(--primary)}.apply-form .form-row{display:grid;grid-template-columns:1fr 1fr;gap:16px}.required{color:var(--danger)}.apply-success{text-align:center;padding:80px 40px;background:var(--gray-50);border-radius:16px}.apply-success h3{font-size:24px;font-weight:800;margin-bottom:16px}.apply-success p{font-size:15px;color:var(--gray-600);line-height:1.8}@media (max-width:768px){.job-card{flex-direction:column}.job-meta{align-items:flex-start;flex-direction:row;flex-wrap:wrap}.apply-form .form-row{grid-template-columns:1fr}} diff --git a/backend/src/main/resources/static/assets/Recruit-DlKGM6KQ.js b/backend/src/main/resources/static/assets/Recruit-DlKGM6KQ.js new file mode 100644 index 00000000..7f12a61c --- /dev/null +++ b/backend/src/main/resources/static/assets/Recruit-DlKGM6KQ.js @@ -0,0 +1 @@ +import{j as e,b as h,a as t,r as d,N as j}from"./index-ChpGil2q.js";/* empty css */const u=[{path:"/recruit/jobs",label:"채용공고"},{path:"/recruit/welfare",label:"복리후생"},{path:"/recruit/apply",label:"지원하기"}];function r({title:a}){return e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"page-hero",children:e.jsxs("div",{className:"container",children:[e.jsx("span",{className:"section-label",children:"Recruit"}),e.jsx("h1",{className:"page-hero-title",children:a}),e.jsx("p",{children:"지오정보기술과 함께 AI 인프라 혁신을 이끌어 갈 인재를 모십니다."})]})}),e.jsx("nav",{className:"sub-nav",children:e.jsx("div",{className:"container",children:u.map(i=>e.jsx(j,{to:i.path,className:({isActive:s})=>"sub-nav-item"+(s?" active":""),children:i.label},i.path))})})]})}const o=[{id:1,title:"AI/LLM 엔지니어",dept:"AI팀",type:"정규직",exp:"경력 3년 이상",stack:["Python","Ollama","LangChain","FastAPI"],desc:"GUARDiA ITSM의 온프레미스 AI 엔진 개발. 자연어→명령 파싱, LLM 파인튜닝, RAG 파이프라인 구축.",deadline:"2026.06.30",hot:!0},{id:2,title:"Java 백엔드 개발자 (Spring Boot)",dept:"개발팀",type:"정규직",exp:"경력 3년 이상",stack:["Java","Spring Boot","Oracle","MyBatis"],desc:"공공기관 SI/SM 프로젝트 백엔드 개발. ERP·CRM·행정정보시스템 구축 및 유지보수.",deadline:"2026.06.30",hot:!0},{id:3,title:"React 프론트엔드 개발자",dept:"개발팀",type:"정규직",exp:"경력 2년 이상",stack:["React","TypeScript","Vite","Chart.js"],desc:"GUARDiA ITSM 및 고객사 포털 프론트엔드 개발. 공공기관 웹접근성(KWCAG 2.1) 준수 필수.",deadline:"2026.06.30",hot:!1},{id:4,title:"인프라 운영 엔지니어 (DBA)",dept:"운영팀",type:"정규직",exp:"경력 3년 이상",stack:["Oracle","Tibero","Linux","Shell"],desc:"Oracle/Tibero DB 설계·튜닝·이관. 삼성전자·국민연금급 대형 DB 운영 경험 우대.",deadline:"2026.06.15",hot:!1},{id:5,title:"PM / PL (공공 SI)",dept:"PM본부",type:"정규직",exp:"경력 5년 이상",stack:["PMP","PMBOK","MS Project","Jira"],desc:"공공기관 정보화사업 PM/PL. 헌법재판소·국민연금·시립대 수준 프로젝트 관리 경험 보유자.",deadline:"2026.06.15",hot:!1},{id:6,title:"DevOps / CI·CD 엔지니어",dept:"개발팀",type:"정규직",exp:"경력 2년 이상",stack:["Docker","Kubernetes","Jenkins","GitHub Actions"],desc:"GUARDiA Vibe CD 파이프라인 구축 및 운영. 폐쇄망 환경 GitOps 경험 우대.",deadline:"상시",hot:!1}];function p(){const[a,i]=d.useState(null);if(a){const s=o.find(l=>l.id===a);return e.jsxs("main",{id:"main-content",className:"inner-page",children:[e.jsx(r,{title:"채용공고"}),e.jsx("section",{className:"section",children:e.jsxs("div",{className:"container",style:{maxWidth:"760px"},children:[e.jsx("button",{className:"notice-back",onClick:()=>i(null),children:"← 목록으로"}),e.jsxs("div",{className:"job-detail-card card",style:{padding:"40px"},children:[e.jsxs("div",{className:"job-detail-header",children:[s.hot&&e.jsx("span",{className:"badge badge-new",children:"HOT"}),e.jsx("h2",{style:{fontSize:"26px",fontWeight:"900",margin:"12px 0 8px"},children:s.title}),e.jsxs("div",{style:{display:"flex",gap:"10px",flexWrap:"wrap"},children:[e.jsx("span",{className:"badge badge-primary",children:s.dept}),e.jsx("span",{className:"badge badge-accent",children:s.type}),e.jsxs("span",{style:{fontSize:"13px",color:"var(--gray-500)"},children:["경력: ",s.exp]}),e.jsxs("span",{style:{fontSize:"13px",color:"var(--gray-500)"},children:["마감: ",s.deadline]})]})]}),e.jsx("div",{className:"divider divider-left",style:{margin:"24px 0"}}),e.jsx("h3",{style:{fontSize:"16px",fontWeight:"700",marginBottom:"12px"},children:"업무 내용"}),e.jsx("p",{style:{color:"var(--gray-700)",lineHeight:"1.8",marginBottom:"28px"},children:s.desc}),e.jsx("h3",{style:{fontSize:"16px",fontWeight:"700",marginBottom:"12px"},children:"기술 스택"}),e.jsx("div",{style:{display:"flex",gap:"8px",flexWrap:"wrap",marginBottom:"28px"},children:s.stack.map((l,n)=>e.jsx("span",{style:{padding:"6px 14px",background:"var(--secondary)",color:"var(--accent)",borderRadius:"6px",fontSize:"13px",fontWeight:"600"},children:l},n))}),e.jsx("h3",{style:{fontSize:"16px",fontWeight:"700",marginBottom:"12px"},children:"지원 방법"}),e.jsxs("p",{style:{color:"var(--gray-700)",lineHeight:"1.8"},children:["이력서 및 포트폴리오를 ",e.jsx("strong",{children:"recruit@zioinfo.co.kr"})," 로 제출하시거나, 아래 지원하기 버튼을 이용해 주십시오."]}),e.jsx("a",{href:"/recruit/apply",className:"btn btn-primary btn-lg",style:{marginTop:"24px",display:"inline-flex"},children:"지원하기 →"})]})]})})]})}return e.jsxs("main",{id:"main-content",className:"inner-page",children:[e.jsx(r,{title:"채용공고"}),e.jsx("section",{className:"section",children:e.jsxs("div",{className:"container",children:[e.jsxs("div",{className:"section-header",children:[e.jsx("span",{className:"section-label",children:"Open Positions"}),e.jsx("h2",{className:"section-title",children:"현재 채용 중인 포지션"})]}),e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:"16px"},children:o.map(s=>e.jsxs("div",{className:"card job-card",onClick:()=>i(s.id),children:[e.jsxs("div",{className:"job-info",children:[e.jsxs("div",{style:{display:"flex",gap:"8px",alignItems:"center",marginBottom:"8px"},children:[s.hot&&e.jsx("span",{className:"badge badge-new",children:"HOT"}),e.jsx("span",{className:"badge badge-primary",children:s.dept}),e.jsx("span",{className:"badge badge-accent",children:s.type})]}),e.jsx("h3",{className:"job-title",children:s.title}),e.jsx("p",{className:"job-desc",children:s.desc}),e.jsx("div",{className:"job-stack",children:s.stack.map((l,n)=>e.jsx("span",{className:"job-tech",children:l},n))})]}),e.jsxs("div",{className:"job-meta",children:[e.jsxs("div",{children:[e.jsx("span",{className:"job-meta-label",children:"경력"}),e.jsx("span",{children:s.exp})]}),e.jsxs("div",{children:[e.jsx("span",{className:"job-meta-label",children:"마감"}),e.jsx("span",{style:{color:s.deadline==="상시"?"var(--accent)":"var(--gray-700)"},children:s.deadline})]}),e.jsx("button",{className:"btn btn-primary btn-sm",children:"상세보기"})]})]},s.id))})]})})]})}const g=[{cat:"💼 근무환경",items:[{icon:"🕘",name:"유연근무제",desc:"코어타임(10시~16시) 외 자유로운 출퇴근 시간 선택"},{icon:"🏠",name:"재택근무",desc:"직무에 따라 주 1~2회 재택근무 지원"},{icon:"💻",name:"장비 지원",desc:"맥북 또는 고성능 윈도우 노트북 선택 지급"},{icon:"🎯",name:"목표 관리(OKR)",desc:"분기별 OKR로 명확한 목표·성과 관리"}]},{cat:"📚 성장 지원",items:[{icon:"📖",name:"교육비 지원",desc:"연 200만원 교육비 지원 (도서, 강의, 세미나)"},{icon:"🏆",name:"자격증 지원",desc:"정보처리기사, PMP, AWS, Oracle 자격증 취득 지원"},{icon:"🎓",name:"사내 강의",desc:"AI·클라우드·보안 월 1회 사내 기술 세미나"},{icon:"✈️",name:"컨퍼런스",desc:"AWS re:Invent, Google I/O 등 국내외 컨퍼런스 참가 지원"}]},{cat:"🎁 복지 혜택",items:[{icon:"🏥",name:"건강검진",desc:"연 1회 종합건강검진 (배우자 포함)"},{icon:"🎂",name:"경조사 지원",desc:"경조금·경조휴가 제공 (결혼, 출산, 상조)"},{icon:"🍽️",name:"식대 지원",desc:"점심 식대 월 15만원 지원 (식권 또는 카드)"},{icon:"🎉",name:"명절 선물",desc:"설·추석 명절 선물 및 상여금 지급"}]}];function N(){return e.jsxs("main",{id:"main-content",className:"inner-page",children:[e.jsx(r,{title:"복리후생"}),e.jsx("section",{className:"section",children:e.jsxs("div",{className:"container",children:[e.jsxs("div",{className:"section-header",children:[e.jsx("span",{className:"section-label",children:"Welfare"}),e.jsx("h2",{className:"section-title",children:"함께 성장하는 환경을 만듭니다"}),e.jsx("p",{className:"section-desc",children:"구성원이 최고의 역량을 발휘할 수 있도록 다양한 지원을 제공합니다"})]}),g.map((a,i)=>e.jsxs("div",{style:{marginBottom:"56px"},children:[e.jsx("h3",{className:"welfare-cat",children:a.cat}),e.jsx("div",{className:"grid-4",children:a.items.map((s,l)=>e.jsxs("div",{className:"card welfare-card",children:[e.jsx("div",{className:"welfare-icon",children:s.icon}),e.jsx("h4",{className:"welfare-name",children:s.name}),e.jsx("p",{className:"welfare-desc",children:s.desc})]},l))})]},i)),e.jsxs("div",{className:"talent-wrap",children:[e.jsxs("div",{className:"section-header",children:[e.jsx("span",{className:"section-label",children:"Talent"}),e.jsx("h2",{className:"section-title",children:"우리가 찾는 인재"})]}),e.jsx("div",{className:"grid-3",children:[{icon:"🔥",title:"도전하는 인재",desc:"새로운 기술과 문제에 두려움 없이 도전하는 분"},{icon:"🤝",title:"협력하는 인재",desc:"팀과 함께 성장하며 지식을 나누는 분"},{icon:"🎯",title:"책임지는 인재",desc:"맡은 업무에 오너십을 갖고 끝까지 완수하는 분"}].map((a,i)=>e.jsxs("div",{className:"card",style:{padding:"36px 28px",textAlign:"center"},children:[e.jsx("div",{style:{fontSize:"48px",marginBottom:"16px"},children:a.icon}),e.jsx("h4",{style:{fontSize:"18px",fontWeight:"800",marginBottom:"12px"},children:a.title}),e.jsx("p",{style:{fontSize:"14px",color:"var(--gray-600)",lineHeight:"1.7"},children:a.desc})]},i))})]})]})})]})}function b(){const[a,i]=d.useState({name:"",email:"",phone:"",position:"",exp:"",portfolio:"",message:""}),[s,l]=d.useState(null),n=c=>i(m=>({...m,[c.target.name]:c.target.value})),x=c=>{c.preventDefault(),l("success")};return e.jsxs("main",{id:"main-content",className:"inner-page",children:[e.jsx(r,{title:"지원하기"}),e.jsx("section",{className:"section",children:e.jsxs("div",{className:"container",style:{maxWidth:"720px"},children:[e.jsxs("div",{className:"section-header",children:[e.jsx("span",{className:"section-label",children:"Apply"}),e.jsx("h2",{className:"section-title",children:"입사 지원서"}),e.jsxs("p",{className:"section-desc",children:["아래 양식을 작성하시거나 ",e.jsx("strong",{children:"recruit@zioinfo.co.kr"}),"로 이력서를 보내주세요"]})]}),s==="success"?e.jsxs("div",{className:"apply-success",children:[e.jsx("div",{style:{fontSize:"64px",marginBottom:"20px"},children:"✅"}),e.jsx("h3",{children:"지원이 완료되었습니다!"}),e.jsxs("p",{children:["검토 후 영업일 기준 3~5일 내에 연락 드리겠습니다.",e.jsx("br",{}),"recruit@zioinfo.co.kr 로도 이력서를 추가 제출하시면 더욱 빠르게 처리됩니다."]}),e.jsx("button",{className:"btn btn-outline",onClick:()=>l(null),style:{marginTop:"24px"},children:"다시 지원하기"})]}):e.jsxs("form",{className:"apply-form card",onSubmit:x,style:{padding:"40px"},children:[e.jsxs("div",{className:"form-row",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{children:["성명 ",e.jsx("span",{className:"required",children:"*"})]}),e.jsx("input",{name:"name",required:!0,value:a.name,onChange:n,placeholder:"홍길동"})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{children:["연락처 ",e.jsx("span",{className:"required",children:"*"})]}),e.jsx("input",{name:"phone",required:!0,value:a.phone,onChange:n,placeholder:"010-0000-0000"})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{children:["이메일 ",e.jsx("span",{className:"required",children:"*"})]}),e.jsx("input",{name:"email",type:"email",required:!0,value:a.email,onChange:n,placeholder:"your@email.com"})]}),e.jsxs("div",{className:"form-row",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{children:["지원 포지션 ",e.jsx("span",{className:"required",children:"*"})]}),e.jsxs("select",{name:"position",required:!0,value:a.position,onChange:n,children:[e.jsx("option",{value:"",children:"선택하세요"}),o.map(c=>e.jsx("option",{value:c.title,children:c.title},c.id)),e.jsx("option",{value:"기타",children:"기타 (자유 지원)"})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"경력 사항"}),e.jsx("input",{name:"exp",value:a.exp,onChange:n,placeholder:"예: 5년 (현대백화점 → 지오정보기술)"})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"포트폴리오 / GitHub URL"}),e.jsx("input",{name:"portfolio",value:a.portfolio,onChange:n,placeholder:"https://github.com/yourname"})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"자기소개 및 지원동기"}),e.jsx("textarea",{name:"message",rows:6,value:a.message,onChange:n,placeholder:"간단한 자기소개와 지원동기를 작성해 주세요."})]}),e.jsx("button",{type:"submit",className:"btn btn-primary btn-lg",style:{width:"100%"},children:"지원서 제출하기"})]})]})})]})}function y(){return e.jsxs(h,{children:[e.jsx(t,{path:"jobs",element:e.jsx(p,{})}),e.jsx(t,{path:"welfare",element:e.jsx(N,{})}),e.jsx(t,{path:"apply",element:e.jsx(b,{})}),e.jsx(t,{path:"*",element:e.jsx(p,{})})]})}export{y as default}; diff --git a/backend/src/main/resources/static/assets/SolutionPage-C7_Wcm8g.css b/backend/src/main/resources/static/assets/SolutionPage-C7_Wcm8g.css new file mode 100644 index 00000000..0b43b6c6 --- /dev/null +++ b/backend/src/main/resources/static/assets/SolutionPage-C7_Wcm8g.css @@ -0,0 +1 @@ +.sol-hero-grid{display:grid;grid-template-columns:1fr 1fr;gap:64px;align-items:center}.sol-title{font-size:clamp(26px,3.5vw,40px);font-weight:900;color:var(--gray-900);line-height:1.25;margin:12px 0 20px}.sol-title em{color:var(--primary);font-style:normal}.sol-desc{font-size:15px;color:var(--gray-600);line-height:1.85;margin-bottom:24px}.sol-features{display:flex;flex-direction:column;gap:10px}.sol-feature-item{display:flex;gap:10px;font-size:14px;color:var(--gray-700)}.sol-check{color:var(--accent);font-weight:700;flex-shrink:0}.sol-module-card{padding:32px 24px}.sol-module-icon{font-size:36px;margin-bottom:16px}.sol-module-card h3{font-size:16px;font-weight:700;margin-bottom:10px;color:var(--gray-900)}.sol-module-card p{font-size:13px;color:var(--gray-600);line-height:1.7}.sol-visual{display:flex;justify-content:center}.sol-screen{background:var(--secondary);border-radius:16px;padding:24px;width:100%;max-width:360px;box-shadow:var(--shadow-lg)}.sol-screen-header{display:flex;align-items:center;gap:8px;margin-bottom:20px;font-size:12px;color:#fff9;font-weight:600}.sol-screen-header span{width:10px;height:10px;border-radius:50%;background:var(--accent);flex-shrink:0}.sol-chart-bar-wrap{display:flex;gap:8px;height:120px;align-items:flex-end;margin-bottom:20px}.sol-chart-bar{flex:1;background:linear-gradient(to top,var(--primary),var(--accent));border-radius:4px 4px 0 0}.sol-stat-row{display:flex;gap:12px}.sol-stat{flex:1;background:#ffffff0f;border-radius:8px;padding:12px;text-align:center}.sol-stat strong{display:block;font-size:14px;color:#fff;font-weight:700}.sol-stat span{font-size:10px;color:#ffffff80;margin-top:4px;display:block}.crm-items{display:flex;flex-direction:column;gap:12px}.crm-item{display:flex;align-items:center;gap:12px;background:#ffffff0d;border-radius:8px;padding:10px 12px}.crm-avatar{width:32px;height:32px;border-radius:50%;background:var(--primary);display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:700;color:#fff;flex-shrink:0}.crm-info{flex:1}.crm-info strong{display:block;font-size:13px;color:#fff;font-weight:600}.crm-info span{font-size:11px;color:#ffffff80}.crm-status{font-size:11px;font-weight:700}.bi-kpis{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:20px}.bi-kpi{background:#ffffff0f;border-radius:8px;padding:12px}.bi-kpi-label{display:block;font-size:10px;color:#ffffff80;margin-bottom:4px}.bi-kpi-val{display:block;font-size:15px;color:#fff;font-weight:700}.bi-kpi-delta{font-size:11px;font-weight:600}.bi-bar-chart{display:flex;gap:12px;height:80px;align-items:flex-end}.bi-bar-group{flex:1;display:flex;flex-direction:column;align-items:center;gap:6px;height:100%}.bi-bar-pair{display:flex;gap:4px;width:100%;height:100%;align-items:flex-end}.bi-bar{flex:1;border-radius:3px 3px 0 0}.bi-bar.revenue{background:var(--accent)}.bi-bar.cost{background:#ef444499}.bi-bar-group span{font-size:10px;color:#ffffff80}@media (max-width: 768px){.sol-hero-grid{grid-template-columns:1fr}.sol-visual{order:-1}} diff --git a/backend/src/main/resources/static/assets/SolutionPage-Da0Vpoc-.js b/backend/src/main/resources/static/assets/SolutionPage-Da0Vpoc-.js new file mode 100644 index 00000000..cc70d8e6 --- /dev/null +++ b/backend/src/main/resources/static/assets/SolutionPage-Da0Vpoc-.js @@ -0,0 +1 @@ +import{j as s,b as r,a as i,L as c,N as d}from"./index-ChpGil2q.js";/* empty css */const t=[{path:"/solution/guardia",label:"GUARDiA ITSM",badge:"NEW"},{path:"/solution/erp",label:"ERP"},{path:"/solution/crm",label:"CRM"},{path:"/solution/bi",label:"BI"}];function n({title:l}){return s.jsxs(s.Fragment,{children:[s.jsx("div",{className:"page-hero",children:s.jsxs("div",{className:"container",children:[s.jsx("span",{className:"section-label",children:"Solution"}),s.jsx("h1",{className:"page-hero-title",children:l})]})}),s.jsx("nav",{className:"sub-nav",children:s.jsx("div",{className:"container",children:t.map(e=>s.jsxs(d,{to:e.path,className:({isActive:a})=>"sub-nav-item"+(a?" active":""),children:[e.label,e.badge&&s.jsx("span",{className:"badge badge-new",style:{marginLeft:"6px",fontSize:"10px"},children:e.badge})]},e.path))})})]})}function o(){const l=[{icon:"💰",name:"재무·회계",desc:"전표처리, 결산, 세무신고, 원가계산 자동화"},{icon:"🏭",name:"생산관리",desc:"BOM 관리, 생산계획, 공정관리, 품질관리"},{icon:"📦",name:"구매·재고",desc:"발주, 입출고, 재고 현황, 협력사 포털"},{icon:"👥",name:"인사·급여",desc:"근태관리, 급여계산, 조직도, 인사평가"},{icon:"🛒",name:"영업·물류",desc:"수주관리, 배송, 매출 분석, 고객 관리"},{icon:"📊",name:"경영 분석",desc:"KPI 대시보드, 예산 vs 실적, 경영 보고서"}];return s.jsxs("main",{id:"main-content",className:"inner-page",children:[s.jsx(n,{title:"ERP 솔루션"}),s.jsx("section",{className:"section",children:s.jsxs("div",{className:"container",children:[s.jsxs("div",{className:"sol-hero-grid",children:[s.jsxs("div",{children:[s.jsx("span",{className:"section-label",children:"Enterprise Resource Planning"}),s.jsxs("h2",{className:"sol-title",children:["공공·중견기업 맞춤형",s.jsx("br",{}),s.jsx("em",{children:"통합 ERP 솔루션"})]}),s.jsx("p",{className:"sol-desc",children:"20년 이상 현대모비스, 한화그룹, 이마트 등 국내 주요 기업의 핵심 업무 시스템을 구축한 경험을 바탕으로, 고객사의 업무 프로세스에 최적화된 맞춤형 ERP를 제공합니다."}),s.jsx("div",{className:"sol-features",children:["공공기관 표준 회계 기준 적용","Oracle / Tibero DB 지원","모바일 결재·보고 지원","기존 레거시 시스템 연계"].map((e,a)=>s.jsxs("div",{className:"sol-feature-item",children:[s.jsx("span",{className:"sol-check",children:"✓"})," ",e]},a))}),s.jsxs("div",{style:{display:"flex",gap:"12px",marginTop:"32px",flexWrap:"wrap"},children:[s.jsx(c,{to:"/support/contact?type=데모 신청",className:"btn btn-primary btn-lg",children:"무료 데모 신청"}),s.jsx(c,{to:"/support/catalog",className:"btn btn-outline btn-lg",children:"카탈로그 다운로드"})]})]}),s.jsx("div",{className:"sol-visual erp-visual",children:s.jsxs("div",{className:"sol-screen",children:[s.jsxs("div",{className:"sol-screen-header",children:[s.jsx("span",{}),"재무 대시보드"]}),s.jsx("div",{className:"sol-chart-bar-wrap",children:[80,65,90,72,88,55,95].map((e,a)=>s.jsx("div",{className:"sol-chart-bar",style:{height:e+"%"}},a))}),s.jsxs("div",{className:"sol-stat-row",children:[s.jsxs("div",{className:"sol-stat",children:[s.jsx("strong",{children:"₩12.4억"}),s.jsx("span",{children:"이번달 매출"})]}),s.jsxs("div",{className:"sol-stat",children:[s.jsx("strong",{children:"98.2%"}),s.jsx("span",{children:"예산 집행률"})]}),s.jsxs("div",{className:"sol-stat",children:[s.jsx("strong",{children:"+18%"}),s.jsx("span",{children:"전월 대비"})]})]})]})})]}),s.jsxs("div",{style:{marginTop:"80px"},children:[s.jsxs("div",{className:"section-header",children:[s.jsx("span",{className:"section-label",children:"Modules"}),s.jsx("h2",{className:"section-title",children:"6대 핵심 모듈"})]}),s.jsx("div",{className:"grid-3",children:l.map((e,a)=>s.jsxs("div",{className:"card sol-module-card",children:[s.jsx("div",{className:"sol-module-icon",children:e.icon}),s.jsx("h3",{children:e.name}),s.jsx("p",{children:e.desc})]},a))})]})]})})]})}function m(){const l=[{icon:"📇",name:"고객 360˚",desc:"고객 정보, 구매이력, 상담이력, 선호도를 단일 뷰로 통합"},{icon:"📞",name:"멀티채널 상담",desc:"전화·이메일·채팅·SNS 통합 인입, 상담 이력 자동 기록"},{icon:"🎯",name:"영업 파이프라인",desc:"리드 발굴부터 계약까지 전 단계 시각화 관리"},{icon:"📨",name:"마케팅 자동화",desc:"고객 세그먼트별 자동 캠페인, 이메일·SMS 발송"},{icon:"🤖",name:"AI 상담 추천",desc:"Ollama LLM 기반 최적 답변 자동 추천 및 요약"},{icon:"📈",name:"성과 분석",desc:"상담사별·채널별 KPI, 고객 만족도, 전환율 리포트"}];return s.jsxs("main",{id:"main-content",className:"inner-page",children:[s.jsx(n,{title:"CRM 솔루션"}),s.jsx("section",{className:"section",children:s.jsxs("div",{className:"container",children:[s.jsxs("div",{className:"sol-hero-grid",children:[s.jsxs("div",{children:[s.jsx("span",{className:"section-label",children:"Customer Relationship Management"}),s.jsxs("h2",{className:"sol-title",children:["AI 기반",s.jsx("br",{}),s.jsx("em",{children:"고객 관계 관리 플랫폼"})]}),s.jsx("p",{className:"sol-desc",children:"삼성전자 차세대 CRM, LG U+ VAN 고도화, 현대캐피탈 차세대 시스템 등 국내 최대 규모 CRM 프로젝트를 성공적으로 수행한 전문 역량으로 구축합니다. 온프레미스 AI(Ollama) 연동으로 데이터 외부 유출 없이 지능형 상담을 실현합니다."}),s.jsx("div",{className:"sol-features",children:["삼성전자·LG·현대 구축 레퍼런스","온프레미스 AI 상담 추천","CTI 연동 (콜센터 솔루션)","공공기관 개인정보보호법 준수"].map((e,a)=>s.jsxs("div",{className:"sol-feature-item",children:[s.jsx("span",{className:"sol-check",children:"✓"})," ",e]},a))}),s.jsxs("div",{style:{display:"flex",gap:"12px",marginTop:"32px",flexWrap:"wrap"},children:[s.jsx(c,{to:"/support/contact?type=데모 신청",className:"btn btn-primary btn-lg",children:"데모 신청"}),s.jsx(c,{to:"/support/catalog",className:"btn btn-outline btn-lg",children:"카탈로그"})]})]}),s.jsx("div",{className:"sol-visual crm-visual",children:s.jsxs("div",{className:"sol-screen",children:[s.jsxs("div",{className:"sol-screen-header",children:[s.jsx("span",{}),"고객 상담 현황"]}),s.jsx("div",{className:"crm-items",children:[{name:"김민준",type:"제품문의",status:"처리중",color:"#f59e0b"},{name:"이서연",type:"기술지원",status:"완료",color:"#10b981"},{name:"박지후",type:"불만접수",status:"대기",color:"#ef4444"},{name:"최수아",type:"데모신청",status:"완료",color:"#10b981"}].map((e,a)=>s.jsxs("div",{className:"crm-item",children:[s.jsx("div",{className:"crm-avatar",children:e.name[0]}),s.jsxs("div",{className:"crm-info",children:[s.jsx("strong",{children:e.name}),s.jsx("span",{children:e.type})]}),s.jsx("span",{className:"crm-status",style:{color:e.color},children:e.status})]},a))})]})})]}),s.jsxs("div",{style:{marginTop:"80px"},children:[s.jsxs("div",{className:"section-header",children:[s.jsx("span",{className:"section-label",children:"Features"}),s.jsx("h2",{className:"section-title",children:"주요 기능"})]}),s.jsx("div",{className:"grid-3",children:l.map((e,a)=>s.jsxs("div",{className:"card sol-module-card",children:[s.jsx("div",{className:"sol-module-icon",children:e.icon}),s.jsx("h3",{children:e.name}),s.jsx("p",{children:e.desc})]},a))})]})]})})]})}function h(){const l=[{icon:"📊",name:"경영 대시보드",desc:"실시간 KPI 모니터링, 부서별 성과 지표, 경영진 요약 보고"},{icon:"📉",name:"매출·비용 분석",desc:"기간별·제품별·채널별 매출 트렌드, 비용 구조 분석"},{icon:"🗺️",name:"지역별 분석",desc:"지도 기반 시각화, 공공기관 지역별 서비스 현황"},{icon:"🔮",name:"AI 예측 분석",desc:"머신러닝 기반 수요 예측, 이상 패턴 자동 탐지"},{icon:"📋",name:"자동 보고서",desc:"일·주·월 보고서 자동 생성, 이메일·메신저 배포"},{icon:"🔗",name:"ETL 파이프라인",desc:"Oracle, SAP, 공공DB 등 다양한 소스 데이터 연계"}];return s.jsxs("main",{id:"main-content",className:"inner-page",children:[s.jsx(n,{title:"BI 솔루션"}),s.jsx("section",{className:"section",children:s.jsxs("div",{className:"container",children:[s.jsxs("div",{className:"sol-hero-grid",children:[s.jsxs("div",{children:[s.jsx("span",{className:"section-label",children:"Business Intelligence"}),s.jsxs("h2",{className:"sol-title",children:["데이터 기반",s.jsx("br",{}),s.jsx("em",{children:"의사결정 플랫폼"})]}),s.jsx("p",{className:"sol-desc",children:"OZ Report, MiPlatform, JasperReports 등 다양한 보고 도구와의 연동 경험을 바탕으로, 공공기관·중견기업 맞춤형 BI 플랫폼을 구축합니다. 기존 레거시 DB에서 실시간 데이터를 수집해 경영 인사이트를 제공합니다."}),s.jsx("div",{className:"sol-features",children:["OZ·MiPlatform·JasperReport 연동","실시간 대시보드 (WebSocket)","Oracle·Tibero·PostgreSQL 지원","공공기관 표준 보고서 양식"].map((e,a)=>s.jsxs("div",{className:"sol-feature-item",children:[s.jsx("span",{className:"sol-check",children:"✓"})," ",e]},a))}),s.jsxs("div",{style:{display:"flex",gap:"12px",marginTop:"32px",flexWrap:"wrap"},children:[s.jsx(c,{to:"/support/contact?type=데모 신청",className:"btn btn-primary btn-lg",children:"데모 신청"}),s.jsx(c,{to:"/support/catalog",className:"btn btn-outline btn-lg",children:"카탈로그"})]})]}),s.jsx("div",{className:"sol-visual bi-visual",children:s.jsxs("div",{className:"sol-screen",children:[s.jsxs("div",{className:"sol-screen-header",children:[s.jsx("span",{}),"경영 대시보드"]}),s.jsx("div",{className:"bi-kpis",children:[{label:"매출",val:"₩48.2억",up:!0,delta:"+12%"},{label:"비용",val:"₩31.7억",up:!1,delta:"-3%"},{label:"이익",val:"₩16.5억",up:!0,delta:"+28%"},{label:"고객",val:"1,240명",up:!0,delta:"+8%"}].map((e,a)=>s.jsxs("div",{className:"bi-kpi",children:[s.jsx("span",{className:"bi-kpi-label",children:e.label}),s.jsx("strong",{className:"bi-kpi-val",children:e.val}),s.jsx("span",{className:"bi-kpi-delta",style:{color:e.up?"#10b981":"#ef4444"},children:e.delta})]},a))}),s.jsx("div",{className:"bi-bar-chart",children:["1Q","2Q","3Q","4Q"].map((e,a)=>s.jsxs("div",{className:"bi-bar-group",children:[s.jsxs("div",{className:"bi-bar-pair",children:[s.jsx("div",{className:"bi-bar revenue",style:{height:[60,75,85,100][a]+"%"}}),s.jsx("div",{className:"bi-bar cost",style:{height:[70,65,60,55][a]+"%"}})]}),s.jsx("span",{children:e})]},a))})]})})]}),s.jsxs("div",{style:{marginTop:"80px"},children:[s.jsxs("div",{className:"section-header",children:[s.jsx("span",{className:"section-label",children:"Features"}),s.jsx("h2",{className:"section-title",children:"주요 기능"})]}),s.jsx("div",{className:"grid-3",children:l.map((e,a)=>s.jsxs("div",{className:"card sol-module-card",children:[s.jsx("div",{className:"sol-module-icon",children:e.icon}),s.jsx("h3",{children:e.name}),s.jsx("p",{children:e.desc})]},a))})]})]})})]})}function p(){return s.jsxs(r,{children:[s.jsx(i,{path:"erp",element:s.jsx(o,{})}),s.jsx(i,{path:"crm",element:s.jsx(m,{})}),s.jsx(i,{path:"bi",element:s.jsx(h,{})})]})}export{p as default}; diff --git a/backend/src/main/resources/static/assets/Support-C5QVP1gW.js b/backend/src/main/resources/static/assets/Support-C5QVP1gW.js new file mode 100644 index 00000000..4b5efb0d --- /dev/null +++ b/backend/src/main/resources/static/assets/Support-C5QVP1gW.js @@ -0,0 +1 @@ +import{j as e,b as j,a as n,r as p,N}from"./index-ChpGil2q.js";/* empty css */const A=[{path:"/support/notice",label:"공지사항"},{path:"/support/faq",label:"FAQ"},{path:"/support/catalog",label:"카탈로그"},{path:"/support/contact",label:"문의하기"}];function h({title:s}){return e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"page-hero",children:e.jsxs("div",{className:"container",children:[e.jsx("span",{className:"section-label",children:"Support"}),e.jsx("h1",{className:"page-hero-title",children:s})]})}),e.jsx("nav",{className:"sub-nav",children:e.jsx("div",{className:"container",children:A.map(t=>e.jsx(N,{to:t.path,className:({isActive:a})=>"sub-nav-item"+(a?" active":""),children:t.label},t.path))})})]})}const u=[{id:1,cat:"공지",title:"GUARDiA ITSM v2.0 정식 출시 안내",date:"2026.05.15",hot:!0},{id:2,cat:"공지",title:"2026년 상반기 유지보수 점검 일정 안내 (6월 1일~2일)",date:"2026.05.10",hot:!1},{id:3,cat:"보안",title:"Apache Log4j 취약점 긴급 패치 안내",date:"2026.04.28",hot:!1},{id:4,cat:"공지",title:"개인정보처리방침 개정 안내 (2026년 4월)",date:"2026.04.01",hot:!1},{id:5,cat:"이벤트",title:"2026 공공기관 디지털전환 세미나 참가 안내 (5월 20일)",date:"2026.03.25",hot:!1},{id:6,cat:"공지",title:"GUARDiA ITSM GS인증 1등급 신청 완료 안내",date:"2026.03.10",hot:!1},{id:7,cat:"공지",title:"신규 파트너사 협약 체결 — Tibero 공식 파트너 등록",date:"2026.02.20",hot:!1},{id:8,cat:"보안",title:"2026년 정보보안 교육 실시 안내 (임직원 필독)",date:"2026.01.15",hot:!1},{id:9,cat:"공지",title:"2025년 사업성과 및 2026년 사업계획 발표",date:"2026.01.02",hot:!1},{id:10,cat:"공지",title:"연말연시 고객지원팀 운영시간 안내 (12/24~1/3)",date:"2025.12.20",hot:!1}],d={공지:"var(--primary)",보안:"var(--danger)",이벤트:"var(--accent)"};function x(){const[s,t]=p.useState(null);return e.jsxs("main",{id:"main-content",className:"inner-page",children:[e.jsx(h,{title:"공지사항"}),e.jsx("section",{className:"section",children:e.jsx("div",{className:"container",style:{maxWidth:"860px"},children:s?e.jsxs("div",{className:"notice-detail",children:[e.jsx("button",{className:"notice-back",onClick:()=>t(null),children:"← 목록으로"}),e.jsxs("div",{className:"notice-detail-header",children:[e.jsx("span",{className:"notice-cat",style:{background:d[s.cat]+"18",color:d[s.cat]},children:s.cat}),e.jsx("h2",{children:s.title}),e.jsx("p",{className:"notice-date",children:s.date})]}),e.jsxs("div",{className:"notice-body",children:[e.jsx("p",{children:"안녕하세요, (주)지오정보기술입니다."}),e.jsxs("p",{children:["본 공지는 ",e.jsx("strong",{children:s.title}),"에 관한 안내입니다."]}),e.jsx("p",{children:"자세한 사항은 고객지원팀(02-784-9271)으로 문의해 주시기 바랍니다."}),e.jsx("p",{children:"감사합니다."})]})]}):e.jsxs("div",{className:"notice-list",children:[e.jsxs("div",{className:"notice-header-row",children:[e.jsx("span",{children:"구분"}),e.jsx("span",{children:"제목"}),e.jsx("span",{children:"등록일"})]}),u.map(a=>e.jsxs("div",{className:"notice-row",onClick:()=>t(a),children:[e.jsx("span",{className:"notice-cat",style:{background:d[a.cat]+"18",color:d[a.cat]},children:a.cat}),e.jsxs("span",{className:"notice-title-text",children:[a.hot&&e.jsx("span",{className:"notice-hot",children:"HOT"}),a.title]}),e.jsx("span",{className:"notice-date",children:a.date})]},a.id))]})})})]})}const v=[{cat:"GUARDiA ITSM",items:[{q:"GUARDiA ITSM은 어떤 제품인가요?",a:"GUARDiA ITSM은 메신저 한 줄 명령으로 1,000개 이상 공공기관의 레거시 IT 인프라를 자동 운영하는 AI 기반 ChatOps 플랫폼입니다. 대상 서버에 별도 소프트웨어 설치 없이 표준 SSH/SFTP 프로토콜만으로 배포·운영·모니터링을 자동화합니다."},{q:"서버에 에이전트를 설치해야 하나요?",a:"아니요. GUARDiA ITSM은 에이전트리스(Agentless) 방식으로 동작합니다. 대상 서버에 어떠한 소프트웨어도 설치할 필요가 없으며, 표준 SSH(22번 포트)만 열려 있으면 즉시 연동 가능합니다."},{q:"클라우드 없이 사용할 수 있나요?",a:"예. GUARDiA ITSM은 완전한 온프레미스(On-premise) 솔루션으로, 외부 클라우드나 인터넷 연결 없이 폐쇄망 환경에서도 100% 동작합니다. AI 엔진(Ollama)도 내부 서버에서 구동됩니다."},{q:"지원되는 운영체제는 무엇인가요?",a:"GUARDiA ITSM 서버: Ubuntu 20.04+, CentOS 7+, RHEL 8+, Windows Server 2019+를 지원합니다. 관리 대상 서버: SSH가 지원되는 모든 Linux/Unix/Windows Server 환경에서 사용 가능합니다."}]},{cat:"도입·계약",items:[{q:"도입 비용은 어떻게 되나요?",a:"기관 규모와 관리 서버 수에 따라 맞춤 견적을 제공합니다. 7일 무료 체험판을 먼저 신청하신 후 문의 주시면 상세한 견적을 안내해 드립니다."},{q:"체험판을 사용할 수 있나요?",a:'예. 7일 무료 체험판을 제공합니다. 문의하기 또는 GUARDiA 페이지의 "무료 데모 신청" 버튼을 통해 신청하시면 영업일 기준 1일 이내에 안내 드립니다.'},{q:"공공기관 나라장터 조달 구매가 가능한가요?",a:"예. GUARDiA ITSM은 조달청 나라장터 등록을 준비 중이며, 공공기관 입찰을 통한 구매를 지원합니다. 자세한 사항은 영업팀(02-784-9271)에 문의해 주십시오."}]},{cat:"기술 지원",items:[{q:"기술 지원은 어떻게 받을 수 있나요?",a:"이메일(support@zioinfo.co.kr), 전화(02-784-9271), GUARDiA ITSM 내 챗봇을 통해 기술 지원을 제공합니다. 운영 중 긴급 장애는 24시간 온콜 지원이 가능합니다."},{q:"업그레이드는 어떻게 진행되나요?",a:"정기 업데이트는 연 2~4회 제공되며, 보안 패치는 즉시 제공됩니다. 업그레이드는 GUARDiA 내 자동 배포 기능을 통해 다운타임 없이 진행할 수 있습니다."}]}];function g(){const[s,t]=p.useState({}),a=(i,c)=>t(l=>({...l,[`${i}-${c}`]:!l[`${i}-${c}`]}));return e.jsxs("main",{id:"main-content",className:"inner-page",children:[e.jsx(h,{title:"자주 묻는 질문"}),e.jsx("section",{className:"section",children:e.jsxs("div",{className:"container",style:{maxWidth:"860px"},children:[e.jsxs("div",{className:"section-header",children:[e.jsx("span",{className:"section-label",children:"FAQ"}),e.jsx("h2",{className:"section-title",children:"자주 묻는 질문"})]}),v.map((i,c)=>e.jsxs("div",{className:"faq-cat-wrap",children:[e.jsx("h3",{className:"faq-cat-title",children:i.cat}),i.items.map((l,r)=>{const m=`${c}-${r}`,o=s[m];return e.jsxs("div",{className:`faq-item ${o?"open":""}`,children:[e.jsxs("button",{className:"faq-q",onClick:()=>a(c,r),children:[e.jsx("span",{className:"faq-icon",children:o?"−":"+"}),l.q]}),o&&e.jsx("div",{className:"faq-a",children:l.a})]},r)})]},c)),e.jsxs("div",{className:"faq-more",children:[e.jsx("p",{children:"원하시는 답변을 찾지 못하셨나요?"}),e.jsx("a",{href:"/support/contact",className:"btn btn-primary",children:"1:1 문의하기"})]})]})})]})}const S=[{title:"GUARDiA ITSM v2.0 제품 카탈로그",desc:"GUARDiA ITSM 전체 기능 및 도입 가이드",pages:"24p",size:"4.2MB",date:"2026.05",icon:"⚡",color:"var(--primary)"},{title:"GUARDiA ITSM 기술 명세서",desc:"API 명세, 아키텍처, 보안 설계 문서",pages:"48p",size:"8.1MB",date:"2026.05",icon:"📐",color:"#7c3aed"},{title:"ERP 솔루션 카탈로그",desc:"공공·중견기업 맞춤형 ERP 모듈 소개",pages:"16p",size:"3.5MB",date:"2026.03",icon:"💰",color:"#059669"},{title:"CRM 솔루션 카탈로그",desc:"AI 기반 고객관리 플랫폼 소개",pages:"12p",size:"2.8MB",date:"2026.03",icon:"📞",color:"#d97706"},{title:"BI 솔루션 카탈로그",desc:"경영 분석 및 대시보드 플랫폼 소개",pages:"12p",size:"2.4MB",date:"2026.02",icon:"📊",color:"#0891b2"},{title:"지오정보기술 회사 소개서",desc:"회사 연혁, 사업 영역, 주요 레퍼런스",pages:"20p",size:"5.6MB",date:"2026.01",icon:"🏢",color:"var(--secondary)"}];function b(){return e.jsxs("main",{id:"main-content",className:"inner-page",children:[e.jsx(h,{title:"카탈로그"}),e.jsx("section",{className:"section",children:e.jsxs("div",{className:"container",children:[e.jsxs("div",{className:"section-header",children:[e.jsx("span",{className:"section-label",children:"Catalog"}),e.jsx("h2",{className:"section-title",children:"자료실"}),e.jsx("p",{className:"section-desc",children:"제품 카탈로그 및 기술 문서를 다운로드하세요"})]}),e.jsx("div",{className:"grid-3",children:S.map((s,t)=>e.jsxs("div",{className:"card catalog-card",children:[e.jsx("div",{className:"catalog-icon-wrap",style:{background:s.color+"18"},children:e.jsx("span",{className:"catalog-icon",style:{color:s.color},children:s.icon})}),e.jsxs("div",{className:"catalog-info",children:[e.jsx("h3",{className:"catalog-title",children:s.title}),e.jsx("p",{className:"catalog-desc",children:s.desc}),e.jsxs("div",{className:"catalog-meta",children:[e.jsx("span",{children:s.pages}),e.jsx("span",{children:s.size}),e.jsx("span",{children:s.date})]})]}),e.jsx("button",{className:"catalog-btn",onClick:()=>alert("문의하기 페이지에서 카탈로그를 요청해주세요."),children:"📥 다운로드"})]},t))}),e.jsxs("div",{className:"catalog-request",children:[e.jsx("h3",{children:"다른 자료가 필요하신가요?"}),e.jsx("p",{children:"NDA 자료, 기술 제안서, 가격표 등 별도 문서는 영업팀에 요청해 주십시오."}),e.jsx("a",{href:"/support/contact",className:"btn btn-outline btn-lg",children:"자료 요청하기"})]})]})})]})}function I(){return e.jsxs(j,{children:[e.jsx(n,{path:"notice",element:e.jsx(x,{})}),e.jsx(n,{path:"faq",element:e.jsx(g,{})}),e.jsx(n,{path:"catalog",element:e.jsx(b,{})}),e.jsx(n,{path:"*",element:e.jsx(x,{})})]})}export{I as default}; diff --git a/backend/src/main/resources/static/assets/Support-DvGESosS.css b/backend/src/main/resources/static/assets/Support-DvGESosS.css new file mode 100644 index 00000000..59db5986 --- /dev/null +++ b/backend/src/main/resources/static/assets/Support-DvGESosS.css @@ -0,0 +1 @@ +.notice-header-row{display:grid;grid-template-columns:80px 1fr 100px;gap:16px;padding:12px 16px;background:var(--gray-50);border-radius:8px 8px 0 0;font-size:12px;font-weight:700;color:var(--gray-500);border:1px solid var(--gray-200);border-bottom:none}.notice-row{display:grid;grid-template-columns:80px 1fr 100px;gap:16px;padding:14px 16px;border:1px solid var(--gray-200);border-top:none;cursor:pointer;align-items:center;transition:background var(--fast)}.notice-row:last-child{border-radius:0 0 8px 8px}.notice-row:hover{background:var(--gray-50)}.notice-cat{display:inline-block;padding:3px 10px;border-radius:12px;font-size:11px;font-weight:700;text-align:center}.notice-title-text{font-size:14px;color:var(--gray-800);display:flex;align-items:center;gap:8px}.notice-hot{background:var(--danger);color:#fff;font-size:10px;padding:2px 6px;border-radius:4px;font-weight:700;flex-shrink:0}.notice-date{font-size:12px;color:var(--gray-500)}.notice-detail{max-width:760px}.notice-back{font-size:14px;color:var(--primary);margin-bottom:24px;display:inline-flex;align-items:center;gap:4px;cursor:pointer;background:none;border:none}.notice-detail-header{border-bottom:2px solid var(--gray-200);padding-bottom:20px;margin-bottom:32px}.notice-detail-header h2{font-size:22px;font-weight:800;margin:12px 0 8px}.notice-body{display:flex;flex-direction:column;gap:16px;font-size:15px;line-height:1.85;color:var(--gray-700)}.faq-cat-wrap{margin-bottom:40px}.faq-cat-title{font-size:16px;font-weight:800;color:var(--primary);margin-bottom:12px;padding-bottom:8px;border-bottom:2px solid var(--primary-light)}.faq-item{border:1px solid var(--gray-200);border-radius:8px;margin-bottom:8px;overflow:hidden;transition:box-shadow var(--fast)}.faq-item.open{box-shadow:var(--shadow);border-color:var(--primary-light)}.faq-q{width:100%;display:flex;align-items:center;gap:14px;padding:16px 20px;font-size:15px;font-weight:600;color:var(--gray-800);text-align:left;background:none;border:none;cursor:pointer;transition:background var(--fast)}.faq-q:hover{background:var(--gray-50)}.faq-icon{width:24px;height:24px;border-radius:50%;background:var(--primary);color:#fff;display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0}.faq-a{padding:0 20px 20px 58px;font-size:14px;color:var(--gray-600);line-height:1.8}.faq-more{text-align:center;padding:48px;background:var(--gray-50);border-radius:12px;margin-top:32px}.faq-more p{color:var(--gray-600);margin-bottom:20px;font-size:16px}.catalog-card{padding:0;display:flex;flex-direction:column}.catalog-icon-wrap{padding:32px;display:flex;align-items:center;justify-content:center}.catalog-icon{font-size:48px}.catalog-info{padding:0 24px 16px;flex:1}.catalog-title{font-size:15px;font-weight:700;margin-bottom:8px;color:var(--gray-900)}.catalog-desc{font-size:13px;color:var(--gray-600);margin-bottom:12px;line-height:1.6}.catalog-meta{display:flex;gap:12px;font-size:12px;color:var(--gray-400)}.catalog-btn{margin:0 16px 20px;padding:12px;border-radius:8px;background:var(--gray-50);border:1px solid var(--gray-200);font-size:14px;font-weight:600;color:var(--primary);cursor:pointer;transition:all var(--fast);text-align:center}.catalog-btn:hover{background:var(--primary);color:#fff;border-color:var(--primary)}.catalog-request{text-align:center;padding:56px;background:var(--gray-50);border-radius:16px;margin-top:48px}.catalog-request h3{font-size:22px;font-weight:800;margin-bottom:12px}.catalog-request p{color:var(--gray-600);margin-bottom:24px} diff --git a/backend/src/main/resources/static/assets/admin-BHL-7hu0.css b/backend/src/main/resources/static/assets/admin-BHL-7hu0.css new file mode 100644 index 00000000..2e0e6217 --- /dev/null +++ b/backend/src/main/resources/static/assets/admin-BHL-7hu0.css @@ -0,0 +1 @@ +:root{--admin-sidebar-w: 220px;--admin-bg: #f0f2f5;--admin-sidebar-bg: #1a1d2e;--admin-sidebar-hover: #2a2d3e;--admin-accent: #4f6ef7;--admin-accent-hover: #3a5be0;--admin-text: #1e293b;--admin-muted: #64748b;--admin-border: #e2e8f0;--admin-card: #ffffff;--admin-danger: #ef4444;--admin-success: #22c55e;--admin-warning: #f59e0b}.admin-wrap{display:flex;min-height:100vh;background:var(--admin-bg);font-family:Pretendard,-apple-system,sans-serif}.admin-sidebar{width:var(--admin-sidebar-w);background:var(--admin-sidebar-bg);display:flex;flex-direction:column;position:fixed;top:0;left:0;height:100vh;z-index:100;transition:transform .25s}.admin-sidebar-logo{padding:20px 20px 16px;border-bottom:1px solid rgba(255,255,255,.08)}.admin-sidebar-logo h2{color:#fff;font-size:15px;font-weight:700;margin:0}.admin-sidebar-logo span{color:#7c85a8;font-size:11px}.admin-nav{flex:1;overflow-y:auto;padding:12px 0}.admin-nav-section{padding:12px 16px 4px;color:#7c85a8;font-size:10px;font-weight:600;letter-spacing:.08em;text-transform:uppercase}.admin-nav a{display:flex;align-items:center;gap:10px;padding:9px 20px;color:#b0b7cc;text-decoration:none;font-size:13.5px;border-radius:0;transition:all .15s}.admin-nav a:hover{background:var(--admin-sidebar-hover);color:#fff}.admin-nav a.active{background:var(--admin-accent);color:#fff}.admin-nav a .nav-icon{width:16px;text-align:center;flex-shrink:0}.admin-nav-badge{background:var(--admin-danger);color:#fff;font-size:10px;padding:1px 6px;border-radius:10px;margin-left:auto}.admin-sidebar-footer{padding:16px 20px;border-top:1px solid rgba(255,255,255,.08)}.admin-sidebar-footer button{width:100%;background:transparent;border:1px solid rgba(255,255,255,.15);color:#b0b7cc;padding:8px 12px;border-radius:6px;font-size:13px;cursor:pointer;transition:all .15s}.admin-sidebar-footer button:hover{background:#ffffff14;color:#fff}.admin-main{margin-left:var(--admin-sidebar-w);flex:1;display:flex;flex-direction:column;min-height:100vh}.admin-topbar{background:var(--admin-card);border-bottom:1px solid var(--admin-border);padding:0 28px;height:56px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:50}.admin-topbar h1{font-size:16px;font-weight:600;color:var(--admin-text);margin:0}.admin-topbar-right{display:flex;align-items:center;gap:12px}.admin-user-badge{background:#e8ecff;color:var(--admin-accent);padding:4px 12px;border-radius:20px;font-size:12px;font-weight:600}.admin-content{padding:28px;flex:1}.admin-card{background:var(--admin-card);border-radius:10px;border:1px solid var(--admin-border);padding:20px}.admin-card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}.admin-card-header h3{font-size:14px;font-weight:600;color:var(--admin-text);margin:0}.admin-stats{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:16px;margin-bottom:24px}.stat-card{background:var(--admin-card);border-radius:10px;padding:20px;border:1px solid var(--admin-border);display:flex;align-items:center;gap:16px}.stat-icon{width:44px;height:44px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:20px;flex-shrink:0}.stat-icon.blue{background:#eff2ff}.stat-icon.green{background:#f0fdf4}.stat-icon.orange{background:#fff7ed}.stat-icon.red{background:#fff1f2}.stat-info h4{font-size:22px;font-weight:700;color:var(--admin-text);margin:0 0 2px}.stat-info p{font-size:12px;color:var(--admin-muted);margin:0}.admin-table-wrap{overflow-x:auto}.admin-table{width:100%;border-collapse:collapse;font-size:13.5px}.admin-table th{background:#f8fafc;color:var(--admin-muted);font-weight:600;font-size:11px;text-transform:uppercase;letter-spacing:.04em;padding:10px 14px;border-bottom:1px solid var(--admin-border);text-align:left;white-space:nowrap}.admin-table td{padding:12px 14px;border-bottom:1px solid #f1f5f9;color:var(--admin-text);vertical-align:middle}.admin-table tr:last-child td{border-bottom:none}.admin-table tr:hover td{background:#f8fafc}.admin-table .truncate{max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:20px;font-size:11px;font-weight:600}.badge-green{background:#dcfce7;color:#16a34a}.badge-red{background:#fee2e2;color:#dc2626}.badge-blue{background:#dbeafe;color:#2563eb}.badge-orange{background:#ffedd5;color:#ea580c}.badge-gray{background:#f1f5f9;color:#64748b}.btn{display:inline-flex;align-items:center;gap:6px;padding:8px 16px;border-radius:7px;font-size:13px;font-weight:500;cursor:pointer;border:none;transition:all .15s;text-decoration:none}.btn-primary{background:var(--admin-accent);color:#fff}.btn-primary:hover{background:var(--admin-accent-hover)}.btn-outline{background:transparent;color:var(--admin-text);border:1px solid var(--admin-border)}.btn-outline:hover{background:#f8fafc}.btn-danger{background:transparent;color:var(--admin-danger);border:1px solid #fecaca}.btn-danger:hover{background:#fff1f2}.btn-sm{padding:5px 10px;font-size:12px}.btn-icon{padding:6px;border-radius:6px}.action-btns{display:flex;gap:6px;align-items:center}.admin-toolbar{display:flex;align-items:center;gap:10px;margin-bottom:16px;flex-wrap:wrap}.admin-toolbar-right{margin-left:auto;display:flex;gap:8px}.admin-search{position:relative}.admin-search input{padding:8px 12px 8px 34px;border:1px solid var(--admin-border);border-radius:7px;font-size:13px;outline:none;width:200px;background:#fff;color:var(--admin-text)}.admin-search input:focus{border-color:var(--admin-accent)}.admin-search-icon{position:absolute;left:10px;top:50%;transform:translateY(-50%);color:var(--admin-muted);font-size:14px}.admin-select{padding:8px 12px;border:1px solid var(--admin-border);border-radius:7px;font-size:13px;outline:none;background:#fff;color:var(--admin-text);cursor:pointer}.admin-select:focus{border-color:var(--admin-accent)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000073;z-index:1000;display:flex;align-items:center;justify-content:center;padding:16px}.modal{background:var(--admin-card);border-radius:12px;width:100%;max-width:640px;max-height:90vh;overflow-y:auto;box-shadow:0 20px 60px #0003}.modal-header{padding:20px 24px 16px;border-bottom:1px solid var(--admin-border);display:flex;align-items:center;justify-content:space-between}.modal-header h3{font-size:15px;font-weight:600;margin:0}.modal-header button{background:none;border:none;cursor:pointer;color:var(--admin-muted);font-size:18px;line-height:1;padding:4px}.modal-body{padding:24px}.modal-footer{padding:16px 24px;border-top:1px solid var(--admin-border);display:flex;justify-content:flex-end;gap:10px}.form-group{margin-bottom:16px}.form-group label{display:block;font-size:12px;font-weight:600;color:var(--admin-muted);text-transform:uppercase;letter-spacing:.04em;margin-bottom:6px}.form-control{width:100%;padding:9px 12px;border:1px solid var(--admin-border);border-radius:7px;font-size:13.5px;color:var(--admin-text);outline:none;box-sizing:border-box;background:#fff;font-family:inherit}.form-control:focus{border-color:var(--admin-accent);box-shadow:0 0 0 3px #4f6ef71f}textarea.form-control{resize:vertical;min-height:100px}.form-row{display:grid;grid-template-columns:1fr 1fr;gap:14px}.form-check{display:flex;align-items:center;gap:8px;font-size:13.5px;cursor:pointer}.form-check input{width:16px;height:16px;cursor:pointer;accent-color:var(--admin-accent)}.admin-pagination{display:flex;align-items:center;justify-content:space-between;margin-top:16px}.admin-pagination-info{font-size:12px;color:var(--admin-muted)}.pagination-btns{display:flex;gap:4px}.pagination-btns button{padding:5px 10px;border:1px solid var(--admin-border);background:#fff;color:var(--admin-text);border-radius:5px;font-size:12px;cursor:pointer;transition:all .15s}.pagination-btns button:hover:not(:disabled){background:var(--admin-accent);color:#fff;border-color:var(--admin-accent)}.pagination-btns button.active{background:var(--admin-accent);color:#fff;border-color:var(--admin-accent)}.pagination-btns button:disabled{opacity:.4;cursor:not-allowed}.admin-login-page{min-height:100vh;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,#1a1d2e,#2a2d4e);padding:16px}.admin-login-box{background:#fff;border-radius:14px;padding:40px 36px;width:100%;max-width:380px;box-shadow:0 20px 60px #0000004d}.admin-login-box .login-logo{text-align:center;margin-bottom:28px}.admin-login-box .login-logo h1{font-size:22px;font-weight:800;color:var(--admin-text);margin:8px 0 4px}.admin-login-box .login-logo p{font-size:12px;color:var(--admin-muted);margin:0}.admin-login-box .login-badge{display:inline-block;background:#eff2ff;color:var(--admin-accent);padding:2px 10px;border-radius:20px;font-size:11px;font-weight:700;margin-bottom:6px}.login-input-group{margin-bottom:14px}.login-input-group label{display:block;font-size:12px;font-weight:600;color:var(--admin-muted);margin-bottom:6px}.login-input-group input{width:100%;padding:11px 14px;border:1.5px solid var(--admin-border);border-radius:8px;font-size:14px;outline:none;box-sizing:border-box;transition:border-color .15s}.login-input-group input:focus{border-color:var(--admin-accent)}.login-btn{width:100%;padding:12px;background:var(--admin-accent);color:#fff;border:none;border-radius:8px;font-size:14px;font-weight:600;cursor:pointer;margin-top:6px;transition:background .15s}.login-btn:hover{background:var(--admin-accent-hover)}.login-error{background:#fff1f2;color:var(--admin-danger);font-size:12.5px;padding:9px 12px;border-radius:7px;margin-bottom:14px;border:1px solid #fecaca}.recent-list{list-style:none;padding:0;margin:0}.recent-list li{display:flex;align-items:center;gap:10px;padding:10px 0;border-bottom:1px solid #f1f5f9;font-size:13px}.recent-list li:last-child{border-bottom:none}.recent-list .rl-dot{width:7px;height:7px;border-radius:50%;background:var(--admin-accent);flex-shrink:0}.recent-list .rl-title{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--admin-text)}.recent-list .rl-meta{color:var(--admin-muted);font-size:11px;white-space:nowrap}.empty-state{text-align:center;padding:48px 0;color:var(--admin-muted)}.empty-state .empty-icon{font-size:40px;margin-bottom:12px}.empty-state p{font-size:13.5px;margin:0}.admin-toast{position:fixed;bottom:24px;right:24px;z-index:9999;display:flex;flex-direction:column;gap:8px}.toast-item{background:#1e293b;color:#fff;padding:12px 20px;border-radius:8px;font-size:13px;animation:slideUp .2s ease;box-shadow:0 4px 16px #0003}.toast-item.success{border-left:3px solid var(--admin-success)}.toast-item.error{border-left:3px solid var(--admin-danger)}@keyframes slideUp{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@media (max-width: 768px){.admin-sidebar{transform:translate(-100%)}.admin-sidebar.open{transform:translate(0)}.admin-main{margin-left:0}.form-row{grid-template-columns:1fr}.admin-stats{grid-template-columns:1fr 1fr}} diff --git a/backend/src/main/resources/static/assets/index-ChpGil2q.js b/backend/src/main/resources/static/assets/index-ChpGil2q.js new file mode 100644 index 00000000..f796ab62 --- /dev/null +++ b/backend/src/main/resources/static/assets/index-ChpGil2q.js @@ -0,0 +1,68 @@ +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Home-BC38QtTl.js","assets/index-DcNlVx-A.js","assets/Home-jagO1aR4.css","assets/GuardiaDetail-5Pm8bk4O.js","assets/GuardiaDetail-Ax0ubrjA.css","assets/SolutionPage-Da0Vpoc-.js","assets/SolutionPage-C7_Wcm8g.css","assets/Common-BmvLh5lB.css","assets/Company-BOdWAIQ4.js","assets/Company-qD6qaVvP.css","assets/Business-EGnXphuY.js","assets/Business-EM7OeA4c.css","assets/Contact-C6p_tBWi.js","assets/Contact-C2ZwoM3_.css","assets/Support-C5QVP1gW.js","assets/Support-DvGESosS.css","assets/NewsPage-mgytOZhS.js","assets/NewsPage-BgXQ2CUT.css","assets/Recruit-DlKGM6KQ.js","assets/Recruit-CbW65yqF.css","assets/AdminLogin-DcRT5LbX.js","assets/admin-BHL-7hu0.css","assets/AdminLayout-uWX9KsdF.js"])))=>i.map(i=>d[i]); +function tf(e,t){for(var n=0;nr[l]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const l of document.querySelectorAll('link[rel="modulepreload"]'))r(l);new MutationObserver(l=>{for(const o of l)if(o.type==="childList")for(const i of o.addedNodes)i.tagName==="LINK"&&i.rel==="modulepreload"&&r(i)}).observe(document,{childList:!0,subtree:!0});function n(l){const o={};return l.integrity&&(o.integrity=l.integrity),l.referrerPolicy&&(o.referrerPolicy=l.referrerPolicy),l.crossOrigin==="use-credentials"?o.credentials="include":l.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function r(l){if(l.ep)return;l.ep=!0;const o=n(l);fetch(l.href,o)}})();function nf(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var La={exports:{}},vl={},Ra={exports:{}},O={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var ar=Symbol.for("react.element"),rf=Symbol.for("react.portal"),lf=Symbol.for("react.fragment"),of=Symbol.for("react.strict_mode"),uf=Symbol.for("react.profiler"),af=Symbol.for("react.provider"),sf=Symbol.for("react.context"),cf=Symbol.for("react.forward_ref"),ff=Symbol.for("react.suspense"),df=Symbol.for("react.memo"),pf=Symbol.for("react.lazy"),uu=Symbol.iterator;function hf(e){return e===null||typeof e!="object"?null:(e=uu&&e[uu]||e["@@iterator"],typeof e=="function"?e:null)}var ja={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},za=Object.assign,Ta={};function mn(e,t,n){this.props=e,this.context=t,this.refs=Ta,this.updater=n||ja}mn.prototype.isReactComponent={};mn.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};mn.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function Oa(){}Oa.prototype=mn.prototype;function si(e,t,n){this.props=e,this.context=t,this.refs=Ta,this.updater=n||ja}var ci=si.prototype=new Oa;ci.constructor=si;za(ci,mn.prototype);ci.isPureReactComponent=!0;var au=Array.isArray,Ia=Object.prototype.hasOwnProperty,fi={current:null},Da={key:!0,ref:!0,__self:!0,__source:!0};function Ma(e,t,n){var r,l={},o=null,i=null;if(t!=null)for(r in t.ref!==void 0&&(i=t.ref),t.key!==void 0&&(o=""+t.key),t)Ia.call(t,r)&&!Da.hasOwnProperty(r)&&(l[r]=t[r]);var u=arguments.length-2;if(u===1)l.children=n;else if(1>>1,q=P[K];if(0>>1;Kl(Fl,T))Ptl(hr,Fl)?(P[K]=hr,P[Pt]=T,K=Pt):(P[K]=Fl,P[Ct]=T,K=Ct);else if(Ptl(hr,T))P[K]=hr,P[Pt]=T,K=Pt;else break e}}return j}function l(P,j){var T=P.sortIndex-j.sortIndex;return T!==0?T:P.id-j.id}if(typeof performance=="object"&&typeof performance.now=="function"){var o=performance;e.unstable_now=function(){return o.now()}}else{var i=Date,u=i.now();e.unstable_now=function(){return i.now()-u}}var a=[],s=[],h=1,p=null,m=3,S=!1,w=!1,k=!1,_=typeof setTimeout=="function"?setTimeout:null,f=typeof clearTimeout=="function"?clearTimeout:null,c=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function d(P){for(var j=n(s);j!==null;){if(j.callback===null)r(s);else if(j.startTime<=P)r(s),j.sortIndex=j.expirationTime,t(a,j);else break;j=n(s)}}function v(P){if(k=!1,d(P),!w)if(n(a)!==null)w=!0,Dl(E);else{var j=n(s);j!==null&&Ml(v,j.startTime-P)}}function E(P,j){w=!1,k&&(k=!1,f(R),R=-1),S=!0;var T=m;try{for(d(j),p=n(a);p!==null&&(!(p.expirationTime>j)||P&&!ge());){var K=p.callback;if(typeof K=="function"){p.callback=null,m=p.priorityLevel;var q=K(p.expirationTime<=j);j=e.unstable_now(),typeof q=="function"?p.callback=q:p===n(a)&&r(a),d(j)}else r(a);p=n(a)}if(p!==null)var pr=!0;else{var Ct=n(s);Ct!==null&&Ml(v,Ct.startTime-j),pr=!1}return pr}finally{p=null,m=T,S=!1}}var N=!1,L=null,R=-1,$=5,z=-1;function ge(){return!(e.unstable_now()-z<$)}function Sn(){if(L!==null){var P=e.unstable_now();z=P;var j=!0;try{j=L(!0,P)}finally{j?kn():(N=!1,L=null)}}else N=!1}var kn;if(typeof c=="function")kn=function(){c(Sn)};else if(typeof MessageChannel<"u"){var iu=new MessageChannel,ef=iu.port2;iu.port1.onmessage=Sn,kn=function(){ef.postMessage(null)}}else kn=function(){_(Sn,0)};function Dl(P){L=P,N||(N=!0,kn())}function Ml(P,j){R=_(function(){P(e.unstable_now())},j)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(P){P.callback=null},e.unstable_continueExecution=function(){w||S||(w=!0,Dl(E))},e.unstable_forceFrameRate=function(P){0>P||125K?(P.sortIndex=T,t(s,P),n(a)===null&&P===n(s)&&(k?(f(R),R=-1):k=!0,Ml(v,T-K))):(P.sortIndex=q,t(a,P),w||S||(w=!0,Dl(E))),P},e.unstable_shouldYield=ge,e.unstable_wrapCallback=function(P){var j=m;return function(){var T=m;m=j;try{return P.apply(this,arguments)}finally{m=T}}}})(Va);Ba.exports=Va;var Pf=Ba.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Nf=g,xe=Pf;function x(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),po=Object.prototype.hasOwnProperty,Lf=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,cu={},fu={};function Rf(e){return po.call(fu,e)?!0:po.call(cu,e)?!1:Lf.test(e)?fu[e]=!0:(cu[e]=!0,!1)}function jf(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function zf(e,t,n,r){if(t===null||typeof t>"u"||jf(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function de(e,t,n,r,l,o,i){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=l,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=o,this.removeEmptyString=i}var re={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){re[e]=new de(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];re[t]=new de(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){re[e]=new de(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){re[e]=new de(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){re[e]=new de(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){re[e]=new de(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){re[e]=new de(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){re[e]=new de(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){re[e]=new de(e,5,!1,e.toLowerCase(),null,!1,!1)});var pi=/[\-:]([a-z])/g;function hi(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(pi,hi);re[t]=new de(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(pi,hi);re[t]=new de(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(pi,hi);re[t]=new de(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){re[e]=new de(e,1,!1,e.toLowerCase(),null,!1,!1)});re.xlinkHref=new de("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){re[e]=new de(e,1,!1,e.toLowerCase(),null,!0,!0)});function mi(e,t,n,r){var l=re.hasOwnProperty(t)?re[t]:null;(l!==null?l.type!==0:r||!(2u||l[i]!==o[u]){var a=` +`+l[i].replace(" at new "," at ");return e.displayName&&a.includes("")&&(a=a.replace("",e.displayName)),a}while(1<=i&&0<=u);break}}}finally{$l=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?jn(e):""}function Tf(e){switch(e.tag){case 5:return jn(e.type);case 16:return jn("Lazy");case 13:return jn("Suspense");case 19:return jn("SuspenseList");case 0:case 2:case 15:return e=Bl(e.type,!1),e;case 11:return e=Bl(e.type.render,!1),e;case 1:return e=Bl(e.type,!0),e;default:return""}}function yo(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Wt:return"Fragment";case Vt:return"Portal";case ho:return"Profiler";case vi:return"StrictMode";case mo:return"Suspense";case vo:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case Qa:return(e.displayName||"Context")+".Consumer";case Ha:return(e._context.displayName||"Context")+".Provider";case yi:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case gi:return t=e.displayName||null,t!==null?t:yo(e.type)||"Memo";case rt:t=e._payload,e=e._init;try{return yo(e(t))}catch{}}return null}function Of(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return yo(t);case 8:return t===vi?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function wt(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function Ya(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function If(e){var t=Ya(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var l=n.get,o=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return l.call(this)},set:function(i){r=""+i,o.call(this,i)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(i){r=""+i},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function yr(e){e._valueTracker||(e._valueTracker=If(e))}function Ga(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=Ya(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Hr(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function go(e,t){var n=t.checked;return H({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function pu(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=wt(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function Xa(e,t){t=t.checked,t!=null&&mi(e,"checked",t,!1)}function wo(e,t){Xa(e,t);var n=wt(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?So(e,t.type,n):t.hasOwnProperty("defaultValue")&&So(e,t.type,wt(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function hu(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function So(e,t,n){(t!=="number"||Hr(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var zn=Array.isArray;function en(e,t,n,r){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=gr.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Hn(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var In={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Df=["Webkit","ms","Moz","O"];Object.keys(In).forEach(function(e){Df.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),In[t]=In[e]})});function ba(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||In.hasOwnProperty(e)&&In[e]?(""+t).trim():t+"px"}function es(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,l=ba(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,l):e[n]=l}}var Mf=H({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Eo(e,t){if(t){if(Mf[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(x(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(x(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(x(61))}if(t.style!=null&&typeof t.style!="object")throw Error(x(62))}}function _o(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Co=null;function wi(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Po=null,tn=null,nn=null;function yu(e){if(e=fr(e)){if(typeof Po!="function")throw Error(x(280));var t=e.stateNode;t&&(t=kl(t),Po(e.stateNode,e.type,t))}}function ts(e){tn?nn?nn.push(e):nn=[e]:tn=e}function ns(){if(tn){var e=tn,t=nn;if(nn=tn=null,yu(e),t)for(e=0;e>>=0,e===0?32:31-(Yf(e)/Gf|0)|0}var wr=64,Sr=4194304;function Tn(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Gr(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,l=e.suspendedLanes,o=e.pingedLanes,i=n&268435455;if(i!==0){var u=i&~l;u!==0?r=Tn(u):(o&=i,o!==0&&(r=Tn(o)))}else i=n&~l,i!==0?r=Tn(i):o!==0&&(r=Tn(o));if(r===0)return 0;if(t!==0&&t!==r&&!(t&l)&&(l=r&-r,o=t&-t,l>=o||l===16&&(o&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function sr(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-Me(t),e[t]=n}function qf(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=Mn),Pu=" ",Nu=!1;function xs(e,t){switch(e){case"keyup":return Pd.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Es(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Ht=!1;function Ld(e,t){switch(e){case"compositionend":return Es(t);case"keypress":return t.which!==32?null:(Nu=!0,Pu);case"textInput":return e=t.data,e===Pu&&Nu?null:e;default:return null}}function Rd(e,t){if(Ht)return e==="compositionend"||!Ni&&xs(e,t)?(e=Ss(),Dr=_i=ut=null,Ht=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=zu(n)}}function Ns(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Ns(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Ls(){for(var e=window,t=Hr();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Hr(e.document)}return t}function Li(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function Ud(e){var t=Ls(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&Ns(n.ownerDocument.documentElement,n)){if(r!==null&&Li(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=n.textContent.length,o=Math.min(r.start,l);r=r.end===void 0?o:Math.min(r.end,l),!e.extend&&o>r&&(l=r,r=o,o=l),l=Tu(n,o);var i=Tu(n,r);l&&i&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==i.node||e.focusOffset!==i.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),o>r?(e.addRange(t),e.extend(i.node,i.offset)):(t.setEnd(i.node,i.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,Qt=null,To=null,Un=null,Oo=!1;function Ou(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Oo||Qt==null||Qt!==Hr(r)||(r=Qt,"selectionStart"in r&&Li(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Un&&Zn(Un,r)||(Un=r,r=Jr(To,"onSelect"),0Gt||(e.current=Ao[Gt],Ao[Gt]=null,Gt--)}function M(e,t){Gt++,Ao[Gt]=e.current,e.current=t}var St={},ae=xt(St),me=xt(!1),It=St;function an(e,t){var n=e.type.contextTypes;if(!n)return St;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var l={},o;for(o in n)l[o]=t[o];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}function ve(e){return e=e.childContextTypes,e!=null}function br(){U(me),U(ae)}function $u(e,t,n){if(ae.current!==St)throw Error(x(168));M(ae,t),M(me,n)}function Fs(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var l in r)if(!(l in t))throw Error(x(108,Of(e)||"Unknown",l));return H({},n,r)}function el(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||St,It=ae.current,M(ae,e),M(me,me.current),!0}function Bu(e,t,n){var r=e.stateNode;if(!r)throw Error(x(169));n?(e=Fs(e,t,It),r.__reactInternalMemoizedMergedChildContext=e,U(me),U(ae),M(ae,e)):U(me),M(me,n)}var Qe=null,xl=!1,to=!1;function Us(e){Qe===null?Qe=[e]:Qe.push(e)}function Zd(e){xl=!0,Us(e)}function Et(){if(!to&&Qe!==null){to=!0;var e=0,t=D;try{var n=Qe;for(D=1;e>=i,l-=i,Ke=1<<32-Me(t)+l|n<R?($=L,L=null):$=L.sibling;var z=m(f,L,d[R],v);if(z===null){L===null&&(L=$);break}e&&L&&z.alternate===null&&t(f,L),c=o(z,c,R),N===null?E=z:N.sibling=z,N=z,L=$}if(R===d.length)return n(f,L),A&&Nt(f,R),E;if(L===null){for(;RR?($=L,L=null):$=L.sibling;var ge=m(f,L,z.value,v);if(ge===null){L===null&&(L=$);break}e&&L&&ge.alternate===null&&t(f,L),c=o(ge,c,R),N===null?E=ge:N.sibling=ge,N=ge,L=$}if(z.done)return n(f,L),A&&Nt(f,R),E;if(L===null){for(;!z.done;R++,z=d.next())z=p(f,z.value,v),z!==null&&(c=o(z,c,R),N===null?E=z:N.sibling=z,N=z);return A&&Nt(f,R),E}for(L=r(f,L);!z.done;R++,z=d.next())z=S(L,f,R,z.value,v),z!==null&&(e&&z.alternate!==null&&L.delete(z.key===null?R:z.key),c=o(z,c,R),N===null?E=z:N.sibling=z,N=z);return e&&L.forEach(function(Sn){return t(f,Sn)}),A&&Nt(f,R),E}function _(f,c,d,v){if(typeof d=="object"&&d!==null&&d.type===Wt&&d.key===null&&(d=d.props.children),typeof d=="object"&&d!==null){switch(d.$$typeof){case vr:e:{for(var E=d.key,N=c;N!==null;){if(N.key===E){if(E=d.type,E===Wt){if(N.tag===7){n(f,N.sibling),c=l(N,d.props.children),c.return=f,f=c;break e}}else if(N.elementType===E||typeof E=="object"&&E!==null&&E.$$typeof===rt&&Hu(E)===N.type){n(f,N.sibling),c=l(N,d.props),c.ref=Nn(f,N,d),c.return=f,f=c;break e}n(f,N);break}else t(f,N);N=N.sibling}d.type===Wt?(c=Ot(d.props.children,f.mode,v,d.key),c.return=f,f=c):(v=Wr(d.type,d.key,d.props,null,f.mode,v),v.ref=Nn(f,c,d),v.return=f,f=v)}return i(f);case Vt:e:{for(N=d.key;c!==null;){if(c.key===N)if(c.tag===4&&c.stateNode.containerInfo===d.containerInfo&&c.stateNode.implementation===d.implementation){n(f,c.sibling),c=l(c,d.children||[]),c.return=f,f=c;break e}else{n(f,c);break}else t(f,c);c=c.sibling}c=so(d,f.mode,v),c.return=f,f=c}return i(f);case rt:return N=d._init,_(f,c,N(d._payload),v)}if(zn(d))return w(f,c,d,v);if(xn(d))return k(f,c,d,v);Nr(f,d)}return typeof d=="string"&&d!==""||typeof d=="number"?(d=""+d,c!==null&&c.tag===6?(n(f,c.sibling),c=l(c,d),c.return=f,f=c):(n(f,c),c=ao(d,f.mode,v),c.return=f,f=c),i(f)):n(f,c)}return _}var cn=Vs(!0),Ws=Vs(!1),rl=xt(null),ll=null,Jt=null,Ti=null;function Oi(){Ti=Jt=ll=null}function Ii(e){var t=rl.current;U(rl),e._currentValue=t}function Vo(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function ln(e,t){ll=e,Ti=Jt=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(he=!0),e.firstContext=null)}function Re(e){var t=e._currentValue;if(Ti!==e)if(e={context:e,memoizedValue:t,next:null},Jt===null){if(ll===null)throw Error(x(308));Jt=e,ll.dependencies={lanes:0,firstContext:e}}else Jt=Jt.next=e;return t}var jt=null;function Di(e){jt===null?jt=[e]:jt.push(e)}function Hs(e,t,n,r){var l=t.interleaved;return l===null?(n.next=n,Di(t)):(n.next=l.next,l.next=n),t.interleaved=n,Je(e,r)}function Je(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var lt=!1;function Mi(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Qs(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Ge(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function ht(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,I&2){var l=r.pending;return l===null?t.next=t:(t.next=l.next,l.next=t),r.pending=t,Je(e,n)}return l=r.interleaved,l===null?(t.next=t,Di(r)):(t.next=l.next,l.next=t),r.interleaved=t,Je(e,n)}function Fr(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,ki(e,n)}}function Qu(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var l=null,o=null;if(n=n.firstBaseUpdate,n!==null){do{var i={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};o===null?l=o=i:o=o.next=i,n=n.next}while(n!==null);o===null?l=o=t:o=o.next=t}else l=o=t;n={baseState:r.baseState,firstBaseUpdate:l,lastBaseUpdate:o,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function ol(e,t,n,r){var l=e.updateQueue;lt=!1;var o=l.firstBaseUpdate,i=l.lastBaseUpdate,u=l.shared.pending;if(u!==null){l.shared.pending=null;var a=u,s=a.next;a.next=null,i===null?o=s:i.next=s,i=a;var h=e.alternate;h!==null&&(h=h.updateQueue,u=h.lastBaseUpdate,u!==i&&(u===null?h.firstBaseUpdate=s:u.next=s,h.lastBaseUpdate=a))}if(o!==null){var p=l.baseState;i=0,h=s=a=null,u=o;do{var m=u.lane,S=u.eventTime;if((r&m)===m){h!==null&&(h=h.next={eventTime:S,lane:0,tag:u.tag,payload:u.payload,callback:u.callback,next:null});e:{var w=e,k=u;switch(m=t,S=n,k.tag){case 1:if(w=k.payload,typeof w=="function"){p=w.call(S,p,m);break e}p=w;break e;case 3:w.flags=w.flags&-65537|128;case 0:if(w=k.payload,m=typeof w=="function"?w.call(S,p,m):w,m==null)break e;p=H({},p,m);break e;case 2:lt=!0}}u.callback!==null&&u.lane!==0&&(e.flags|=64,m=l.effects,m===null?l.effects=[u]:m.push(u))}else S={eventTime:S,lane:m,tag:u.tag,payload:u.payload,callback:u.callback,next:null},h===null?(s=h=S,a=p):h=h.next=S,i|=m;if(u=u.next,u===null){if(u=l.shared.pending,u===null)break;m=u,u=m.next,m.next=null,l.lastBaseUpdate=m,l.shared.pending=null}}while(!0);if(h===null&&(a=p),l.baseState=a,l.firstBaseUpdate=s,l.lastBaseUpdate=h,t=l.shared.interleaved,t!==null){l=t;do i|=l.lane,l=l.next;while(l!==t)}else o===null&&(l.shared.lanes=0);Ft|=i,e.lanes=i,e.memoizedState=p}}function Ku(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=ro.transition;ro.transition={};try{e(!1),t()}finally{D=n,ro.transition=r}}function ac(){return je().memoizedState}function ep(e,t,n){var r=vt(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},sc(e))cc(t,n);else if(n=Hs(e,t,n,r),n!==null){var l=ce();Fe(n,e,r,l),fc(n,t,r)}}function tp(e,t,n){var r=vt(e),l={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(sc(e))cc(t,l);else{var o=e.alternate;if(e.lanes===0&&(o===null||o.lanes===0)&&(o=t.lastRenderedReducer,o!==null))try{var i=t.lastRenderedState,u=o(i,n);if(l.hasEagerState=!0,l.eagerState=u,Ue(u,i)){var a=t.interleaved;a===null?(l.next=l,Di(t)):(l.next=a.next,a.next=l),t.interleaved=l;return}}catch{}finally{}n=Hs(e,t,l,r),n!==null&&(l=ce(),Fe(n,e,r,l),fc(n,t,r))}}function sc(e){var t=e.alternate;return e===V||t!==null&&t===V}function cc(e,t){An=ul=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function fc(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,ki(e,n)}}var al={readContext:Re,useCallback:oe,useContext:oe,useEffect:oe,useImperativeHandle:oe,useInsertionEffect:oe,useLayoutEffect:oe,useMemo:oe,useReducer:oe,useRef:oe,useState:oe,useDebugValue:oe,useDeferredValue:oe,useTransition:oe,useMutableSource:oe,useSyncExternalStore:oe,useId:oe,unstable_isNewReconciler:!1},np={readContext:Re,useCallback:function(e,t){return $e().memoizedState=[e,t===void 0?null:t],e},useContext:Re,useEffect:Gu,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Ar(4194308,4,rc.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Ar(4194308,4,e,t)},useInsertionEffect:function(e,t){return Ar(4,2,e,t)},useMemo:function(e,t){var n=$e();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=$e();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=ep.bind(null,V,e),[r.memoizedState,e]},useRef:function(e){var t=$e();return e={current:e},t.memoizedState=e},useState:Yu,useDebugValue:Hi,useDeferredValue:function(e){return $e().memoizedState=e},useTransition:function(){var e=Yu(!1),t=e[0];return e=bd.bind(null,e[1]),$e().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=V,l=$e();if(A){if(n===void 0)throw Error(x(407));n=n()}else{if(n=t(),ee===null)throw Error(x(349));Mt&30||Xs(r,t,n)}l.memoizedState=n;var o={value:n,getSnapshot:t};return l.queue=o,Gu(Js.bind(null,r,o,e),[e]),r.flags|=2048,lr(9,Zs.bind(null,r,o,n,t),void 0,null),n},useId:function(){var e=$e(),t=ee.identifierPrefix;if(A){var n=Ye,r=Ke;n=(r&~(1<<32-Me(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=nr++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=i.createElement(n,{is:r.is}):(e=i.createElement(n),n==="select"&&(i=e,r.multiple?i.multiple=!0:r.size&&(i.size=r.size))):e=i.createElementNS(e,n),e[Be]=t,e[bn]=r,kc(e,t,!1,!1),t.stateNode=e;e:{switch(i=_o(n,r),n){case"dialog":F("cancel",e),F("close",e),l=r;break;case"iframe":case"object":case"embed":F("load",e),l=r;break;case"video":case"audio":for(l=0;lpn&&(t.flags|=128,r=!0,Ln(o,!1),t.lanes=4194304)}else{if(!r)if(e=il(i),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),Ln(o,!0),o.tail===null&&o.tailMode==="hidden"&&!i.alternate&&!A)return ie(t),null}else 2*Y()-o.renderingStartTime>pn&&n!==1073741824&&(t.flags|=128,r=!0,Ln(o,!1),t.lanes=4194304);o.isBackwards?(i.sibling=t.child,t.child=i):(n=o.last,n!==null?n.sibling=i:t.child=i,o.last=i)}return o.tail!==null?(t=o.tail,o.rendering=t,o.tail=t.sibling,o.renderingStartTime=Y(),t.sibling=null,n=B.current,M(B,r?n&1|2:n&1),t):(ie(t),null);case 22:case 23:return Zi(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?we&1073741824&&(ie(t),t.subtreeFlags&6&&(t.flags|=8192)):ie(t),null;case 24:return null;case 25:return null}throw Error(x(156,t.tag))}function cp(e,t){switch(ji(t),t.tag){case 1:return ve(t.type)&&br(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return fn(),U(me),U(ae),Ai(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return Ui(t),null;case 13:if(U(B),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(x(340));sn()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return U(B),null;case 4:return fn(),null;case 10:return Ii(t.type._context),null;case 22:case 23:return Zi(),null;case 24:return null;default:return null}}var Rr=!1,ue=!1,fp=typeof WeakSet=="function"?WeakSet:Set,C=null;function qt(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){Q(e,t,r)}else n.current=null}function Jo(e,t,n){try{n()}catch(r){Q(e,t,r)}}var oa=!1;function dp(e,t){if(Io=Xr,e=Ls(),Li(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var l=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break e}var i=0,u=-1,a=-1,s=0,h=0,p=e,m=null;t:for(;;){for(var S;p!==n||l!==0&&p.nodeType!==3||(u=i+l),p!==o||r!==0&&p.nodeType!==3||(a=i+r),p.nodeType===3&&(i+=p.nodeValue.length),(S=p.firstChild)!==null;)m=p,p=S;for(;;){if(p===e)break t;if(m===n&&++s===l&&(u=i),m===o&&++h===r&&(a=i),(S=p.nextSibling)!==null)break;p=m,m=p.parentNode}p=S}n=u===-1||a===-1?null:{start:u,end:a}}else n=null}n=n||{start:0,end:0}}else n=null;for(Do={focusedElem:e,selectionRange:n},Xr=!1,C=t;C!==null;)if(t=C,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,C=e;else for(;C!==null;){t=C;try{var w=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(w!==null){var k=w.memoizedProps,_=w.memoizedState,f=t.stateNode,c=f.getSnapshotBeforeUpdate(t.elementType===t.type?k:Te(t.type,k),_);f.__reactInternalSnapshotBeforeUpdate=c}break;case 3:var d=t.stateNode.containerInfo;d.nodeType===1?d.textContent="":d.nodeType===9&&d.documentElement&&d.removeChild(d.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(x(163))}}catch(v){Q(t,t.return,v)}if(e=t.sibling,e!==null){e.return=t.return,C=e;break}C=t.return}return w=oa,oa=!1,w}function $n(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var o=l.destroy;l.destroy=void 0,o!==void 0&&Jo(t,n,o)}l=l.next}while(l!==r)}}function Cl(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function qo(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function _c(e){var t=e.alternate;t!==null&&(e.alternate=null,_c(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Be],delete t[bn],delete t[Uo],delete t[Gd],delete t[Xd])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Cc(e){return e.tag===5||e.tag===3||e.tag===4}function ia(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Cc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function bo(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=qr));else if(r!==4&&(e=e.child,e!==null))for(bo(e,t,n),e=e.sibling;e!==null;)bo(e,t,n),e=e.sibling}function ei(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(ei(e,t,n),e=e.sibling;e!==null;)ei(e,t,n),e=e.sibling}var te=null,Oe=!1;function nt(e,t,n){for(n=n.child;n!==null;)Pc(e,t,n),n=n.sibling}function Pc(e,t,n){if(Ve&&typeof Ve.onCommitFiberUnmount=="function")try{Ve.onCommitFiberUnmount(yl,n)}catch{}switch(n.tag){case 5:ue||qt(n,t);case 6:var r=te,l=Oe;te=null,nt(e,t,n),te=r,Oe=l,te!==null&&(Oe?(e=te,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):te.removeChild(n.stateNode));break;case 18:te!==null&&(Oe?(e=te,n=n.stateNode,e.nodeType===8?eo(e.parentNode,n):e.nodeType===1&&eo(e,n),Gn(e)):eo(te,n.stateNode));break;case 4:r=te,l=Oe,te=n.stateNode.containerInfo,Oe=!0,nt(e,t,n),te=r,Oe=l;break;case 0:case 11:case 14:case 15:if(!ue&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var o=l,i=o.destroy;o=o.tag,i!==void 0&&(o&2||o&4)&&Jo(n,t,i),l=l.next}while(l!==r)}nt(e,t,n);break;case 1:if(!ue&&(qt(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(u){Q(n,t,u)}nt(e,t,n);break;case 21:nt(e,t,n);break;case 22:n.mode&1?(ue=(r=ue)||n.memoizedState!==null,nt(e,t,n),ue=r):nt(e,t,n);break;default:nt(e,t,n)}}function ua(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new fp),t.forEach(function(r){var l=kp.bind(null,e,r);n.has(r)||(n.add(r),r.then(l,l))})}}function ze(e,t){var n=t.deletions;if(n!==null)for(var r=0;rl&&(l=i),r&=~o}if(r=l,r=Y()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*hp(r/1960))-r,10e?16:e,at===null)var r=!1;else{if(e=at,at=null,fl=0,I&6)throw Error(x(331));var l=I;for(I|=4,C=e.current;C!==null;){var o=C,i=o.child;if(C.flags&16){var u=o.deletions;if(u!==null){for(var a=0;aY()-Gi?Tt(e,0):Yi|=n),ye(e,t)}function Ic(e,t){t===0&&(e.mode&1?(t=Sr,Sr<<=1,!(Sr&130023424)&&(Sr=4194304)):t=1);var n=ce();e=Je(e,t),e!==null&&(sr(e,t,n),ye(e,n))}function Sp(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Ic(e,n)}function kp(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(n=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(x(314))}r!==null&&r.delete(t),Ic(e,n)}var Dc;Dc=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||me.current)he=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return he=!1,ap(e,t,n);he=!!(e.flags&131072)}else he=!1,A&&t.flags&1048576&&As(t,nl,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;$r(e,t),e=t.pendingProps;var l=an(t,ae.current);ln(t,n),l=Bi(null,t,r,e,l,n);var o=Vi();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,ve(r)?(o=!0,el(t)):o=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,Mi(t),l.updater=_l,t.stateNode=l,l._reactInternals=t,Ho(t,r,e,n),t=Yo(null,t,r,!0,o,n)):(t.tag=0,A&&o&&Ri(t),se(null,t,l,n),t=t.child),t;case 16:r=t.elementType;e:{switch($r(e,t),e=t.pendingProps,l=r._init,r=l(r._payload),t.type=r,l=t.tag=Ep(r),e=Te(r,e),l){case 0:t=Ko(null,t,r,e,n);break e;case 1:t=na(null,t,r,e,n);break e;case 11:t=ea(null,t,r,e,n);break e;case 14:t=ta(null,t,r,Te(r.type,e),n);break e}throw Error(x(306,r,""))}return t;case 0:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Te(r,l),Ko(e,t,r,l,n);case 1:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Te(r,l),na(e,t,r,l,n);case 3:e:{if(gc(t),e===null)throw Error(x(387));r=t.pendingProps,o=t.memoizedState,l=o.element,Qs(e,t),ol(t,r,null,n);var i=t.memoizedState;if(r=i.element,o.isDehydrated)if(o={element:r,isDehydrated:!1,cache:i.cache,pendingSuspenseBoundaries:i.pendingSuspenseBoundaries,transitions:i.transitions},t.updateQueue.baseState=o,t.memoizedState=o,t.flags&256){l=dn(Error(x(423)),t),t=ra(e,t,r,n,l);break e}else if(r!==l){l=dn(Error(x(424)),t),t=ra(e,t,r,n,l);break e}else for(Se=pt(t.stateNode.containerInfo.firstChild),ke=t,A=!0,Ie=null,n=Ws(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(sn(),r===l){t=qe(e,t,n);break e}se(e,t,r,n)}t=t.child}return t;case 5:return Ks(t),e===null&&Bo(t),r=t.type,l=t.pendingProps,o=e!==null?e.memoizedProps:null,i=l.children,Mo(r,l)?i=null:o!==null&&Mo(r,o)&&(t.flags|=32),yc(e,t),se(e,t,i,n),t.child;case 6:return e===null&&Bo(t),null;case 13:return wc(e,t,n);case 4:return Fi(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=cn(t,null,r,n):se(e,t,r,n),t.child;case 11:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Te(r,l),ea(e,t,r,l,n);case 7:return se(e,t,t.pendingProps,n),t.child;case 8:return se(e,t,t.pendingProps.children,n),t.child;case 12:return se(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,l=t.pendingProps,o=t.memoizedProps,i=l.value,M(rl,r._currentValue),r._currentValue=i,o!==null)if(Ue(o.value,i)){if(o.children===l.children&&!me.current){t=qe(e,t,n);break e}}else for(o=t.child,o!==null&&(o.return=t);o!==null;){var u=o.dependencies;if(u!==null){i=o.child;for(var a=u.firstContext;a!==null;){if(a.context===r){if(o.tag===1){a=Ge(-1,n&-n),a.tag=2;var s=o.updateQueue;if(s!==null){s=s.shared;var h=s.pending;h===null?a.next=a:(a.next=h.next,h.next=a),s.pending=a}}o.lanes|=n,a=o.alternate,a!==null&&(a.lanes|=n),Vo(o.return,n,t),u.lanes|=n;break}a=a.next}}else if(o.tag===10)i=o.type===t.type?null:o.child;else if(o.tag===18){if(i=o.return,i===null)throw Error(x(341));i.lanes|=n,u=i.alternate,u!==null&&(u.lanes|=n),Vo(i,n,t),i=o.sibling}else i=o.child;if(i!==null)i.return=o;else for(i=o;i!==null;){if(i===t){i=null;break}if(o=i.sibling,o!==null){o.return=i.return,i=o;break}i=i.return}o=i}se(e,t,l.children,n),t=t.child}return t;case 9:return l=t.type,r=t.pendingProps.children,ln(t,n),l=Re(l),r=r(l),t.flags|=1,se(e,t,r,n),t.child;case 14:return r=t.type,l=Te(r,t.pendingProps),l=Te(r.type,l),ta(e,t,r,l,n);case 15:return mc(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Te(r,l),$r(e,t),t.tag=1,ve(r)?(e=!0,el(t)):e=!1,ln(t,n),dc(t,r,l),Ho(t,r,l,n),Yo(null,t,r,!0,e,n);case 19:return Sc(e,t,n);case 22:return vc(e,t,n)}throw Error(x(156,t.tag))};function Mc(e,t){return ss(e,t)}function xp(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Ne(e,t,n,r){return new xp(e,t,n,r)}function qi(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Ep(e){if(typeof e=="function")return qi(e)?1:0;if(e!=null){if(e=e.$$typeof,e===yi)return 11;if(e===gi)return 14}return 2}function yt(e,t){var n=e.alternate;return n===null?(n=Ne(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Wr(e,t,n,r,l,o){var i=2;if(r=e,typeof e=="function")qi(e)&&(i=1);else if(typeof e=="string")i=5;else e:switch(e){case Wt:return Ot(n.children,l,o,t);case vi:i=8,l|=8;break;case ho:return e=Ne(12,n,t,l|2),e.elementType=ho,e.lanes=o,e;case mo:return e=Ne(13,n,t,l),e.elementType=mo,e.lanes=o,e;case vo:return e=Ne(19,n,t,l),e.elementType=vo,e.lanes=o,e;case Ka:return Nl(n,l,o,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case Ha:i=10;break e;case Qa:i=9;break e;case yi:i=11;break e;case gi:i=14;break e;case rt:i=16,r=null;break e}throw Error(x(130,e==null?e:typeof e,""))}return t=Ne(i,n,t,l),t.elementType=e,t.type=r,t.lanes=o,t}function Ot(e,t,n,r){return e=Ne(7,e,r,t),e.lanes=n,e}function Nl(e,t,n,r){return e=Ne(22,e,r,t),e.elementType=Ka,e.lanes=n,e.stateNode={isHidden:!1},e}function ao(e,t,n){return e=Ne(6,e,null,t),e.lanes=n,e}function so(e,t,n){return t=Ne(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function _p(e,t,n,r,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Wl(0),this.expirationTimes=Wl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Wl(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function bi(e,t,n,r,l,o,i,u,a){return e=new _p(e,t,n,u,a),t===1?(t=1,o===!0&&(t|=8)):t=0,o=Ne(3,null,null,t),e.current=o,o.stateNode=e,o.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},Mi(o),e}function Cp(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE($c)}catch(e){console.error(e)}}$c(),$a.exports=Ee;var jp=$a.exports,ma=jp;fo.createRoot=ma.createRoot,fo.hydrateRoot=ma.hydrateRoot;/** + * @remix-run/router v1.23.3 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function ir(){return ir=Object.assign?Object.assign.bind():function(e){for(var t=1;t"u")throw new Error(t)}function ru(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function Tp(){return Math.random().toString(36).substr(2,8)}function ya(e,t){return{usr:e.state,key:e.key,idx:t}}function oi(e,t,n,r){return n===void 0&&(n=null),ir({pathname:typeof e=="string"?e:e.pathname,search:"",hash:""},typeof t=="string"?gn(t):t,{state:n,key:t&&t.key||r||Tp()})}function hl(e){let{pathname:t="/",search:n="",hash:r=""}=e;return n&&n!=="?"&&(t+=n.charAt(0)==="?"?n:"?"+n),r&&r!=="#"&&(t+=r.charAt(0)==="#"?r:"#"+r),t}function gn(e){let t={};if(e){let n=e.indexOf("#");n>=0&&(t.hash=e.substr(n),e=e.substr(0,n));let r=e.indexOf("?");r>=0&&(t.search=e.substr(r),e=e.substr(0,r)),e&&(t.pathname=e)}return t}function Op(e,t,n,r){r===void 0&&(r={});let{window:l=document.defaultView,v5Compat:o=!1}=r,i=l.history,u=st.Pop,a=null,s=h();s==null&&(s=0,i.replaceState(ir({},i.state,{idx:s}),""));function h(){return(i.state||{idx:null}).idx}function p(){u=st.Pop;let _=h(),f=_==null?null:_-s;s=_,a&&a({action:u,location:k.location,delta:f})}function m(_,f){u=st.Push;let c=oi(k.location,_,f);s=h()+1;let d=ya(c,s),v=k.createHref(c);try{i.pushState(d,"",v)}catch(E){if(E instanceof DOMException&&E.name==="DataCloneError")throw E;l.location.assign(v)}o&&a&&a({action:u,location:k.location,delta:1})}function S(_,f){u=st.Replace;let c=oi(k.location,_,f);s=h();let d=ya(c,s),v=k.createHref(c);i.replaceState(d,"",v),o&&a&&a({action:u,location:k.location,delta:0})}function w(_){let f=l.location.origin!=="null"?l.location.origin:l.location.href,c=typeof _=="string"?_:hl(_);return c=c.replace(/ $/,"%20"),W(f,"No window.location.(origin|href) available to create URL for href: "+c),new URL(c,f)}let k={get action(){return u},get location(){return e(l,i)},listen(_){if(a)throw new Error("A history only accepts one active listener");return l.addEventListener(va,p),a=_,()=>{l.removeEventListener(va,p),a=null}},createHref(_){return t(l,_)},createURL:w,encodeLocation(_){let f=w(_);return{pathname:f.pathname,search:f.search,hash:f.hash}},push:m,replace:S,go(_){return i.go(_)}};return k}var ga;(function(e){e.data="data",e.deferred="deferred",e.redirect="redirect",e.error="error"})(ga||(ga={}));function Ip(e,t,n){return n===void 0&&(n="/"),Dp(e,t,n)}function Dp(e,t,n,r){let l=typeof t=="string"?gn(t):t,o=hn(l.pathname||"/",n);if(o==null)return null;let i=Bc(e);Mp(i);let u=null,a=Yp(o);for(let s=0;u==null&&s{let a={relativePath:u===void 0?o.path||"":u,caseSensitive:o.caseSensitive===!0,childrenIndex:i,route:o};a.relativePath.startsWith("/")&&(W(a.relativePath.startsWith(r),'Absolute route path "'+a.relativePath+'" nested under path '+('"'+r+'" is not valid. An absolute child route path ')+"must start with the combined path of all its parent routes."),a.relativePath=a.relativePath.slice(r.length));let s=gt([r,a.relativePath]),h=n.concat(a);o.children&&o.children.length>0&&(W(o.index!==!0,"Index routes must not have child routes. Please remove "+('all child routes from route path "'+s+'".')),Bc(o.children,t,h,s)),!(o.path==null&&!o.index)&&t.push({path:s,score:Wp(s,o.index),routesMeta:h})};return e.forEach((o,i)=>{var u;if(o.path===""||!((u=o.path)!=null&&u.includes("?")))l(o,i);else for(let a of Vc(o.path))l(o,i,a)}),t}function Vc(e){let t=e.split("/");if(t.length===0)return[];let[n,...r]=t,l=n.endsWith("?"),o=n.replace(/\?$/,"");if(r.length===0)return l?[o,""]:[o];let i=Vc(r.join("/")),u=[];return u.push(...i.map(a=>a===""?o:[o,a].join("/"))),l&&u.push(...i),u.map(a=>e.startsWith("/")&&a===""?"/":a)}function Mp(e){e.sort((t,n)=>t.score!==n.score?n.score-t.score:Hp(t.routesMeta.map(r=>r.childrenIndex),n.routesMeta.map(r=>r.childrenIndex)))}const Fp=/^:[\w-]+$/,Up=3,Ap=2,$p=1,Bp=10,Vp=-2,wa=e=>e==="*";function Wp(e,t){let n=e.split("/"),r=n.length;return n.some(wa)&&(r+=Vp),t&&(r+=Ap),n.filter(l=>!wa(l)).reduce((l,o)=>l+(Fp.test(o)?Up:o===""?$p:Bp),r)}function Hp(e,t){return e.length===t.length&&e.slice(0,-1).every((r,l)=>r===t[l])?e[e.length-1]-t[t.length-1]:0}function Qp(e,t,n){let{routesMeta:r}=e,l={},o="/",i=[];for(let u=0;u{let{paramName:m,isOptional:S}=h;if(m==="*"){let k=u[p]||"";i=o.slice(0,o.length-k.length).replace(/(.)\/+$/,"$1")}const w=u[p];return S&&!w?s[m]=void 0:s[m]=(w||"").replace(/%2F/g,"/"),s},{}),pathname:o,pathnameBase:i,pattern:e}}function Kp(e,t,n){t===void 0&&(t=!1),n===void 0&&(n=!0),ru(e==="*"||!e.endsWith("*")||e.endsWith("/*"),'Route path "'+e+'" will be treated as if it were '+('"'+e.replace(/\*$/,"/*")+'" because the `*` character must ')+"always follow a `/` in the pattern. To get rid of this warning, "+('please change the route path to "'+e.replace(/\*$/,"/*")+'".'));let r=[],l="^"+e.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(i,u,a)=>(r.push({paramName:u,isOptional:a!=null}),a?"/?([^\\/]+)?":"/([^\\/]+)"));return e.endsWith("*")?(r.push({paramName:"*"}),l+=e==="*"||e==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?l+="\\/*$":e!==""&&e!=="/"&&(l+="(?:(?=\\/|$))"),[new RegExp(l,t?void 0:"i"),r]}function Yp(e){try{return e.split("/").map(t=>decodeURIComponent(t).replace(/\//g,"%2F")).join("/")}catch(t){return ru(!1,'The URL path "'+e+'" could not be decoded because it is is a malformed URL segment. This is probably due to a bad percent '+("encoding ("+t+").")),e}}function hn(e,t){if(t==="/")return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith("/")?t.length-1:t.length,r=e.charAt(n);return r&&r!=="/"?null:e.slice(n)||"/"}const Gp=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,Xp=e=>Gp.test(e);function Zp(e,t){t===void 0&&(t="/");let{pathname:n,search:r="",hash:l=""}=typeof e=="string"?gn(e):e,o;if(n)if(Xp(n))o=n;else{if(n.includes("//")){let i=n;n=Wc(n),ru(!1,"Pathnames cannot have embedded double slashes - normalizing "+(i+" -> "+n))}n.startsWith("/")?o=Sa(n.substring(1),"/"):o=Sa(n,t)}else o=t;return{pathname:o,search:bp(r),hash:eh(l)}}function Sa(e,t){let n=t.replace(/\/+$/,"").split("/");return e.split("/").forEach(l=>{l===".."?n.length>1&&n.pop():l!=="."&&n.push(l)}),n.length>1?n.join("/"):"/"}function co(e,t,n,r){return"Cannot include a '"+e+"' character in a manually specified "+("`to."+t+"` field ["+JSON.stringify(r)+"]. Please separate it out to the ")+("`to."+n+"` field. Alternatively you may provide the full path as ")+'a string in and the router will parse it for you.'}function Jp(e){return e.filter((t,n)=>n===0||t.route.path&&t.route.path.length>0)}function lu(e,t){let n=Jp(e);return t?n.map((r,l)=>l===n.length-1?r.pathname:r.pathnameBase):n.map(r=>r.pathnameBase)}function ou(e,t,n,r){r===void 0&&(r=!1);let l;typeof e=="string"?l=gn(e):(l=ir({},e),W(!l.pathname||!l.pathname.includes("?"),co("?","pathname","search",l)),W(!l.pathname||!l.pathname.includes("#"),co("#","pathname","hash",l)),W(!l.search||!l.search.includes("#"),co("#","search","hash",l)));let o=e===""||l.pathname==="",i=o?"/":l.pathname,u;if(i==null)u=n;else{let p=t.length-1;if(!r&&i.startsWith("..")){let m=i.split("/");for(;m[0]==="..";)m.shift(),p-=1;l.pathname=m.join("/")}u=p>=0?t[p]:"/"}let a=Zp(l,u),s=i&&i!=="/"&&i.endsWith("/"),h=(o||i===".")&&n.endsWith("/");return!a.pathname.endsWith("/")&&(s||h)&&(a.pathname+="/"),a}const Wc=e=>e.replace(/\/\/+/g,"/"),gt=e=>Wc(e.join("/")),qp=e=>e.replace(/\/+$/,"").replace(/^\/*/,"/"),bp=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,eh=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e;function th(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.internal=="boolean"&&"data"in e}const Hc=["post","put","patch","delete"];new Set(Hc);const nh=["get",...Hc];new Set(nh);/** + * React Router v6.30.4 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function ur(){return ur=Object.assign?Object.assign.bind():function(e){for(var t=1;t{u.current=!0}),g.useCallback(function(s,h){if(h===void 0&&(h={}),!u.current)return;if(typeof s=="number"){r.go(s);return}let p=ou(s,JSON.parse(i),o,h.relative==="path");e==null&&t!=="/"&&(p.pathname=p.pathname==="/"?t:gt([t,p.pathname])),(h.replace?r.replace:r.push)(p,h.state,h)},[t,r,i,o,e])}const oh=g.createContext(null);function ih(e){let t=g.useContext(tt).outlet;return t&&g.createElement(oh.Provider,{value:e},t)}function Il(e,t){let{relative:n}=t===void 0?{}:t,{future:r}=g.useContext(et),{matches:l}=g.useContext(tt),{pathname:o}=_t(),i=JSON.stringify(lu(l,r.v7_relativeSplatPath));return g.useMemo(()=>ou(e,JSON.parse(i),o,n==="path"),[e,i,o,n])}function uh(e,t){return ah(e,t)}function ah(e,t,n,r){wn()||W(!1);let{navigator:l}=g.useContext(et),{matches:o}=g.useContext(tt),i=o[o.length-1],u=i?i.params:{};i&&i.pathname;let a=i?i.pathnameBase:"/";i&&i.route;let s=_t(),h;if(t){var p;let _=typeof t=="string"?gn(t):t;a==="/"||(p=_.pathname)!=null&&p.startsWith(a)||W(!1),h=_}else h=s;let m=h.pathname||"/",S=m;if(a!=="/"){let _=a.replace(/^\//,"").split("/");S="/"+m.replace(/^\//,"").split("/").slice(_.length).join("/")}let w=Ip(e,{pathname:S}),k=ph(w&&w.map(_=>Object.assign({},_,{params:Object.assign({},u,_.params),pathname:gt([a,l.encodeLocation?l.encodeLocation(_.pathname).pathname:_.pathname]),pathnameBase:_.pathnameBase==="/"?a:gt([a,l.encodeLocation?l.encodeLocation(_.pathnameBase).pathname:_.pathnameBase])})),o,n,r);return t&&k?g.createElement(Ol.Provider,{value:{location:ur({pathname:"/",search:"",hash:"",state:null,key:"default"},h),navigationType:st.Pop}},k):k}function sh(){let e=yh(),t=th(e)?e.status+" "+e.statusText:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,l={padding:"0.5rem",backgroundColor:"rgba(200,200,200, 0.5)"};return g.createElement(g.Fragment,null,g.createElement("h2",null,"Unexpected Application Error!"),g.createElement("h3",{style:{fontStyle:"italic"}},t),n?g.createElement("pre",{style:l},n):null,null)}const ch=g.createElement(sh,null);class fh extends g.Component{constructor(t){super(t),this.state={location:t.location,revalidation:t.revalidation,error:t.error}}static getDerivedStateFromError(t){return{error:t}}static getDerivedStateFromProps(t,n){return n.location!==t.location||n.revalidation!=="idle"&&t.revalidation==="idle"?{error:t.error,location:t.location,revalidation:t.revalidation}:{error:t.error!==void 0?t.error:n.error,location:n.location,revalidation:t.revalidation||n.revalidation}}componentDidCatch(t,n){console.error("React Router caught the following error during render",t,n)}render(){return this.state.error!==void 0?g.createElement(tt.Provider,{value:this.props.routeContext},g.createElement(Kc.Provider,{value:this.state.error,children:this.props.component})):this.props.children}}function dh(e){let{routeContext:t,match:n,children:r}=e,l=g.useContext(Tl);return l&&l.static&&l.staticContext&&(n.route.errorElement||n.route.ErrorBoundary)&&(l.staticContext._deepestRenderedBoundaryId=n.route.id),g.createElement(tt.Provider,{value:t},r)}function ph(e,t,n,r){var l;if(t===void 0&&(t=[]),n===void 0&&(n=null),r===void 0&&(r=null),e==null){var o;if(!n)return null;if(n.errors)e=n.matches;else if((o=r)!=null&&o.v7_partialHydration&&t.length===0&&!n.initialized&&n.matches.length>0)e=n.matches;else return null}let i=e,u=(l=n)==null?void 0:l.errors;if(u!=null){let h=i.findIndex(p=>p.route.id&&(u==null?void 0:u[p.route.id])!==void 0);h>=0||W(!1),i=i.slice(0,Math.min(i.length,h+1))}let a=!1,s=-1;if(n&&r&&r.v7_partialHydration)for(let h=0;h=0?i=i.slice(0,s+1):i=[i[0]];break}}}return i.reduceRight((h,p,m)=>{let S,w=!1,k=null,_=null;n&&(S=u&&p.route.id?u[p.route.id]:void 0,k=p.route.errorElement||ch,a&&(s<0&&m===0?(wh("route-fallback"),w=!0,_=null):s===m&&(w=!0,_=p.route.hydrateFallbackElement||null)));let f=t.concat(i.slice(0,m+1)),c=()=>{let d;return S?d=k:w?d=_:p.route.Component?d=g.createElement(p.route.Component,null):p.route.element?d=p.route.element:d=h,g.createElement(dh,{match:p,routeContext:{outlet:h,matches:f,isDataRoute:n!=null},children:d})};return n&&(p.route.ErrorBoundary||p.route.errorElement||m===0)?g.createElement(fh,{location:n.location,revalidation:n.revalidation,component:k,error:S,children:c(),routeContext:{outlet:null,matches:f,isDataRoute:!0}}):c()},null)}var Xc=function(e){return e.UseBlocker="useBlocker",e.UseRevalidator="useRevalidator",e.UseNavigateStable="useNavigate",e}(Xc||{}),Zc=function(e){return e.UseBlocker="useBlocker",e.UseLoaderData="useLoaderData",e.UseActionData="useActionData",e.UseRouteError="useRouteError",e.UseNavigation="useNavigation",e.UseRouteLoaderData="useRouteLoaderData",e.UseMatches="useMatches",e.UseRevalidator="useRevalidator",e.UseNavigateStable="useNavigate",e.UseRouteId="useRouteId",e}(Zc||{});function hh(e){let t=g.useContext(Tl);return t||W(!1),t}function mh(e){let t=g.useContext(Qc);return t||W(!1),t}function vh(e){let t=g.useContext(tt);return t||W(!1),t}function Jc(e){let t=vh(),n=t.matches[t.matches.length-1];return n.route.id||W(!1),n.route.id}function yh(){var e;let t=g.useContext(Kc),n=mh(),r=Jc();return t!==void 0?t:(e=n.errors)==null?void 0:e[r]}function gh(){let{router:e}=hh(Xc.UseNavigateStable),t=Jc(Zc.UseNavigateStable),n=g.useRef(!1);return Yc(()=>{n.current=!0}),g.useCallback(function(l,o){o===void 0&&(o={}),n.current&&(typeof l=="number"?e.navigate(l):e.navigate(l,ur({fromRouteId:t},o)))},[e,t])}const ka={};function wh(e,t,n){ka[e]||(ka[e]=!0)}function Sh(e,t){e==null||e.v7_startTransition,e==null||e.v7_relativeSplatPath}function xa(e){let{to:t,replace:n,state:r,relative:l}=e;wn()||W(!1);let{future:o,static:i}=g.useContext(et),{matches:u}=g.useContext(tt),{pathname:a}=_t(),s=Gc(),h=ou(t,lu(u,o.v7_relativeSplatPath),a,l==="path"),p=JSON.stringify(h);return g.useEffect(()=>s(JSON.parse(p),{replace:n,state:r,relative:l}),[s,p,l,n,r]),null}function om(e){return ih(e.context)}function G(e){W(!1)}function kh(e){let{basename:t="/",children:n=null,location:r,navigationType:l=st.Pop,navigator:o,static:i=!1,future:u}=e;wn()&&W(!1);let a=t.replace(/^\/*/,"/"),s=g.useMemo(()=>({basename:a,navigator:o,static:i,future:ur({v7_relativeSplatPath:!1},u)}),[a,u,o,i]);typeof r=="string"&&(r=gn(r));let{pathname:h="/",search:p="",hash:m="",state:S=null,key:w="default"}=r,k=g.useMemo(()=>{let _=hn(h,a);return _==null?null:{location:{pathname:_,search:p,hash:m,state:S,key:w},navigationType:l}},[a,h,p,m,S,w,l]);return k==null?null:g.createElement(et.Provider,{value:s},g.createElement(Ol.Provider,{children:n,value:k}))}function Ea(e){let{children:t,location:n}=e;return uh(ui(t),n)}new Promise(()=>{});function ui(e,t){t===void 0&&(t=[]);let n=[];return g.Children.forEach(e,(r,l)=>{if(!g.isValidElement(r))return;let o=[...t,l];if(r.type===g.Fragment){n.push.apply(n,ui(r.props.children,o));return}r.type!==G&&W(!1),!r.props.index||!r.props.children||W(!1);let i={id:r.props.id||o.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,loader:r.props.loader,action:r.props.action,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(i.children=ui(r.props.children,o)),n.push(i)}),n}/** + * React Router DOM v6.30.4 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function ml(){return ml=Object.assign?Object.assign.bind():function(e){for(var t=1;t{s&&_a?_a(()=>a(p)):a(p)},[a,s]);return g.useLayoutEffect(()=>i.listen(h),[i,h]),g.useEffect(()=>Sh(r),[r]),g.createElement(kh,{basename:t,children:n,location:u.location,navigationType:u.action,navigator:i,future:r})}const jh=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",zh=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,De=g.forwardRef(function(t,n){let{onClick:r,relative:l,reloadDocument:o,replace:i,state:u,target:a,to:s,preventScrollReset:h,viewTransition:p}=t,m=qc(t,_h),{basename:S}=g.useContext(et),w,k=!1;if(typeof s=="string"&&zh.test(s)&&(w=s,jh))try{let d=new URL(window.location.href),v=s.startsWith("//")?new URL(d.protocol+s):new URL(s),E=hn(v.pathname,S);v.origin===d.origin&&E!=null?s=E+v.search+v.hash:k=!0}catch{}let _=rh(s,{relative:l}),f=Oh(s,{replace:i,state:u,target:a,preventScrollReset:h,relative:l,viewTransition:p});function c(d){r&&r(d),d.defaultPrevented||f(d)}return g.createElement("a",ml({},m,{href:w||_,onClick:k||o?r:c,ref:n,target:a}))}),im=g.forwardRef(function(t,n){let{"aria-current":r="page",caseSensitive:l=!1,className:o="",end:i=!1,style:u,to:a,viewTransition:s,children:h}=t,p=qc(t,Ch),m=Il(a,{relative:p.relative}),S=_t(),w=g.useContext(Qc),{navigator:k,basename:_}=g.useContext(et),f=w!=null&&Ih(m)&&s===!0,c=k.encodeLocation?k.encodeLocation(m).pathname:m.pathname,d=S.pathname,v=w&&w.navigation&&w.navigation.location?w.navigation.location.pathname:null;l||(d=d.toLowerCase(),v=v?v.toLowerCase():null,c=c.toLowerCase()),v&&_&&(v=hn(v,_)||v);const E=c!=="/"&&c.endsWith("/")?c.length-1:c.length;let N=d===c||!i&&d.startsWith(c)&&d.charAt(E)==="/",L=v!=null&&(v===c||!i&&v.startsWith(c)&&v.charAt(c.length)==="/"),R={isActive:N,isPending:L,isTransitioning:f},$=N?r:void 0,z;typeof o=="function"?z=o(R):z=[o,N?"active":null,L?"pending":null,f?"transitioning":null].filter(Boolean).join(" ");let ge=typeof u=="function"?u(R):u;return g.createElement(De,ml({},p,{"aria-current":$,className:z,ref:n,style:ge,to:a,viewTransition:s}),typeof h=="function"?h(R):h)});var ai;(function(e){e.UseScrollRestoration="useScrollRestoration",e.UseSubmit="useSubmit",e.UseSubmitFetcher="useSubmitFetcher",e.UseFetcher="useFetcher",e.useViewTransitionState="useViewTransitionState"})(ai||(ai={}));var Ca;(function(e){e.UseFetcher="useFetcher",e.UseFetchers="useFetchers",e.UseScrollRestoration="useScrollRestoration"})(Ca||(Ca={}));function Th(e){let t=g.useContext(Tl);return t||W(!1),t}function Oh(e,t){let{target:n,replace:r,state:l,preventScrollReset:o,relative:i,viewTransition:u}=t===void 0?{}:t,a=Gc(),s=_t(),h=Il(e,{relative:i});return g.useCallback(p=>{if(Eh(p,n)){p.preventDefault();let m=r!==void 0?r:hl(s)===hl(h);a(e,{replace:m,state:l,preventScrollReset:o,relative:i,viewTransition:u})}},[s,a,h,r,l,n,e,o,i,u])}function Ih(e,t){t===void 0&&(t={});let n=g.useContext(Nh);n==null&&W(!1);let{basename:r}=Th(ai.useViewTransitionState),l=Il(e,{relative:t.relative});if(!n.isTransitioning)return!1;let o=hn(n.currentLocation.pathname,r)||n.currentLocation.pathname,i=hn(n.nextLocation.pathname,r)||n.nextLocation.pathname;return ii(l.pathname,i)!=null||ii(l.pathname,o)!=null}const Dh="modulepreload",Mh=function(e){return"/"+e},Pa={},le=function(t,n,r){let l=Promise.resolve();if(n&&n.length>0){document.getElementsByTagName("link");const i=document.querySelector("meta[property=csp-nonce]"),u=(i==null?void 0:i.nonce)||(i==null?void 0:i.getAttribute("nonce"));l=Promise.allSettled(n.map(a=>{if(a=Mh(a),a in Pa)return;Pa[a]=!0;const s=a.endsWith(".css"),h=s?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${a}"]${h}`))return;const p=document.createElement("link");if(p.rel=s?"stylesheet":Dh,s||(p.as="script"),p.crossOrigin="",p.href=a,u&&p.setAttribute("nonce",u),document.head.appendChild(p),s)return new Promise((m,S)=>{p.addEventListener("load",m),p.addEventListener("error",()=>S(new Error(`Unable to preload CSS for ${a}`)))})}))}function o(i){const u=new Event("vite:preloadError",{cancelable:!0});if(u.payload=i,window.dispatchEvent(u),!u.defaultPrevented)throw i}return l.then(i=>{for(const u of i||[])u.status==="rejected"&&o(u.reason);return t().catch(o)})},Na=[{id:"company",label:"회사소개",children:[{label:"CEO 인사말",path:"/company/greeting"},{label:"연혁",path:"/company/history"},{label:"조직도",path:"/company/organization"},{label:"CI 소개",path:"/company/ci"},{label:"오시는 길",path:"/company/location"}]},{id:"solution",label:"솔루션",children:[{label:"GUARDiA ITSM",path:"/solution/guardia",badge:"NEW"},{label:"ERP",path:"/solution/erp"},{label:"CRM",path:"/solution/crm"},{label:"BI",path:"/solution/bi"}]},{id:"business",label:"사업실적",children:[{label:"구축 레퍼런스",path:"/business/reference"},{label:"파트너",path:"/business/partner"}]},{id:"support",label:"고객지원",children:[{label:"공지사항",path:"/support/notice"},{label:"FAQ",path:"/support/faq"},{label:"카탈로그",path:"/support/catalog"},{label:"문의하기",path:"/support/contact"}]},{id:"recruit",label:"채용",children:[{label:"채용공고",path:"/recruit/jobs"},{label:"복리후생",path:"/recruit/welfare"},{label:"지원하기",path:"/recruit/apply"}]},{id:"news",label:"뉴스",children:[{label:"뉴스룸",path:"/news/newsroom"},{label:"기술 블로그",path:"/news/blog"}]}];function Fh(){const[e,t]=g.useState(!1),[n,r]=g.useState(null),[l,o]=g.useState(!1),i=_t();g.useEffect(()=>{const a=()=>t(window.scrollY>60);return window.addEventListener("scroll",a,{passive:!0}),()=>window.removeEventListener("scroll",a)},[]),g.useEffect(()=>{o(!1),r(null)},[i]);const u=a=>{var s;return(s=a.children)==null?void 0:s.some(h=>i.pathname.startsWith(h.path))};return y.jsxs(y.Fragment,{children:[y.jsx("a",{href:"#main-content",className:"skip-link",children:"본문 바로가기"}),y.jsxs("header",{className:`header ${e?"scrolled":""} ${l?"mobile-open":""}`,role:"banner",children:[y.jsxs("div",{className:"header-inner container",children:[y.jsxs(De,{to:"/",className:"logo","aria-label":"(주)지오정보기술 홈으로",children:[y.jsx("img",{src:"/logo.png",alt:"(주)지오정보기술 로고",height:"40",onError:a=>{a.target.style.display="none",a.target.nextSibling.style.display="flex"}}),y.jsxs("span",{className:"logo-text",style:{display:"none"},children:[y.jsx("strong",{children:"Zio"}),"Info"]})]}),y.jsx("nav",{className:"nav-desktop",role:"navigation","aria-label":"주요 메뉴",children:Na.map(a=>y.jsxs("div",{className:`nav-item ${u(a)?"active":""}`,onMouseEnter:()=>r(a.id),onMouseLeave:()=>r(null),children:[y.jsx("button",{className:"nav-trigger","aria-haspopup":"true","aria-expanded":n===a.id,children:a.label}),n===a.id&&y.jsx("div",{className:"dropdown",role:"menu",children:a.children.map(s=>y.jsxs(De,{to:s.path,className:`dropdown-item ${i.pathname===s.path?"current":""}`,role:"menuitem",children:[s.label,s.badge&&y.jsx("span",{className:"badge badge-new",children:s.badge})]},s.path))})]},a.id))}),y.jsx(De,{to:"/support/contact",className:"btn btn-primary btn-sm header-cta",children:"문의하기"}),y.jsxs("button",{className:"hamburger","aria-label":"모바일 메뉴","aria-expanded":l,onClick:()=>o(a=>!a),children:[y.jsx("span",{}),y.jsx("span",{}),y.jsx("span",{})]})]}),l&&y.jsxs("nav",{className:"nav-mobile",role:"navigation","aria-label":"모바일 메뉴",children:[Na.map(a=>y.jsxs("details",{className:"mobile-group",children:[y.jsx("summary",{className:"mobile-group-header",children:a.label}),y.jsx("div",{className:"mobile-children",children:a.children.map(s=>y.jsxs(De,{to:s.path,className:"mobile-child",children:[s.label,s.badge&&y.jsx("span",{className:"badge badge-new",children:s.badge})]},s.path))})]},a.id)),y.jsx(De,{to:"/support/contact",className:"btn btn-primary",style:{margin:"16px"},children:"문의하기"})]})]})]})}const Uh=[{title:"회사소개",links:[{label:"CEO 인사말",path:"/company/greeting"},{label:"연혁",path:"/company/history"},{label:"조직도",path:"/company/organization"},{label:"오시는 길",path:"/company/location"}]},{title:"솔루션",links:[{label:"GUARDiA ITSM",path:"/solution/guardia"},{label:"ERP",path:"/solution/erp"},{label:"CRM",path:"/solution/crm"},{label:"BI",path:"/solution/bi"}]},{title:"고객지원",links:[{label:"공지사항",path:"/support/notice"},{label:"FAQ",path:"/support/faq"},{label:"카탈로그",path:"/support/catalog"},{label:"문의하기",path:"/support/contact"}]},{title:"채용",links:[{label:"채용공고",path:"/recruit/jobs"},{label:"복리후생",path:"/recruit/welfare"},{label:"지원하기",path:"/recruit/apply"}]}];function Ah(){return y.jsxs("footer",{className:"footer",role:"contentinfo",children:[y.jsx("div",{className:"footer-top",children:y.jsxs("div",{className:"container footer-top-inner",children:[y.jsxs("div",{className:"footer-brand",children:[y.jsxs(De,{to:"/",className:"footer-logo",children:[y.jsx("img",{src:"/logo-white.png",alt:"(주)지오정보기술 로고",height:"36",onError:e=>{e.target.style.display="none",e.target.nextSibling.style.display="block"}}),y.jsxs("span",{className:"footer-logo-text",style:{display:"none"},children:[y.jsx("strong",{children:"Zio"}),"Info"]})]}),y.jsxs("p",{className:"footer-tagline",children:["AI 기반 레거시 인프라 자율 운영 플랫폼",y.jsx("br",{}),"GUARDiA ITSM으로 공공기관 IT를 혁신합니다."]}),y.jsxs("div",{className:"footer-contact-list",children:[y.jsxs("div",{className:"footer-contact-item",children:[y.jsx("span",{className:"contact-label",children:"대표전화"}),y.jsx("span",{children:"02-000-0000"})]}),y.jsxs("div",{className:"footer-contact-item",children:[y.jsx("span",{className:"contact-label",children:"이메일"}),y.jsx("a",{href:"mailto:info@zioinfo.co.kr",children:"info@zioinfo.co.kr"})]}),y.jsxs("div",{className:"footer-contact-item",children:[y.jsx("span",{className:"contact-label",children:"주소"}),y.jsx("span",{children:"서울특별시"})]})]})]}),Uh.map((e,t)=>y.jsxs("div",{className:"footer-menu-group",children:[y.jsx("h3",{className:"footer-menu-title",children:e.title}),y.jsx("ul",{className:"footer-menu-list",children:e.links.map((n,r)=>y.jsx("li",{children:y.jsx(De,{to:n.path,children:n.label})},r))})]},t))]})}),y.jsx("div",{className:"footer-bottom",children:y.jsxs("div",{className:"container footer-bottom-inner",children:[y.jsxs("div",{className:"footer-legal",children:[y.jsx(De,{to:"/privacy",children:"개인정보처리방침"}),y.jsx(De,{to:"/terms",children:"이용약관"}),y.jsx(De,{to:"/sitemap",children:"사이트맵"})]}),y.jsx("p",{className:"footer-copyright",children:"Copyright © 2026 (주)지오정보기술 All Rights Reserved."}),y.jsxs("div",{className:"footer-powered",children:["Powered by ",y.jsx("strong",{children:"GUARDiA ITSM"})]})]})})]})}const $h=g.lazy(()=>le(()=>import("./Home-BC38QtTl.js"),__vite__mapDeps([0,1,2]))),Bh=g.lazy(()=>le(()=>import("./GuardiaDetail-5Pm8bk4O.js"),__vite__mapDeps([3,4]))),Vh=g.lazy(()=>le(()=>import("./SolutionPage-Da0Vpoc-.js"),__vite__mapDeps([5,6,7]))),Wh=g.lazy(()=>le(()=>import("./Company-BOdWAIQ4.js"),__vite__mapDeps([8,9,7]))),Hh=g.lazy(()=>le(()=>import("./Business-EGnXphuY.js"),__vite__mapDeps([10,11,7]))),Qh=g.lazy(()=>le(()=>import("./Contact-C6p_tBWi.js"),__vite__mapDeps([12,1,13]))),Kh=g.lazy(()=>le(()=>import("./Support-C5QVP1gW.js"),__vite__mapDeps([14,15,7]))),Yh=g.lazy(()=>le(()=>import("./NewsPage-mgytOZhS.js"),__vite__mapDeps([16,17,7]))),Gh=g.lazy(()=>le(()=>import("./Recruit-DlKGM6KQ.js"),__vite__mapDeps([18,19,7]))),Xh=g.lazy(()=>le(()=>import("./NotFound-KZZDVQMb.js"),[])),Zh=g.lazy(()=>le(()=>import("./AdminLogin-DcRT5LbX.js"),__vite__mapDeps([20,21]))),Jh=g.lazy(()=>le(()=>import("./AdminLayout-uWX9KsdF.js"),__vite__mapDeps([22,21]))),qh=g.lazy(()=>le(()=>import("./AdminDashboard-B5ryl_KI.js"),[])),bh=g.lazy(()=>le(()=>import("./AdminNews-CDSgPR9E.js"),[])),em=g.lazy(()=>le(()=>import("./AdminInquiry-BBFBdE8S.js"),[])),tm=g.lazy(()=>le(()=>import("./AdminRecruit-CfX4mhQb.js"),[])),nm=g.lazy(()=>le(()=>import("./AdminSettings-DaHEGHsg.js"),[]));function bc(){return y.jsx("div",{style:{display:"flex",alignItems:"center",justifyContent:"center",height:"60vh",color:"var(--gray-400)",fontSize:"14px"},children:"로딩 중..."})}function rm({children:e}){return y.jsxs(y.Fragment,{children:[y.jsx(Fh,{}),y.jsx(g.Suspense,{fallback:y.jsx(bc,{}),children:e}),y.jsx(Ah,{})]})}function lm(){return _t().pathname.startsWith("/admin")?y.jsx(g.Suspense,{fallback:y.jsx(bc,{}),children:y.jsxs(Ea,{children:[y.jsx(G,{path:"/admin/login",element:y.jsx(Zh,{})}),y.jsxs(G,{path:"/admin",element:y.jsx(Jh,{}),children:[y.jsx(G,{index:!0,element:y.jsx(xa,{to:"/admin/dashboard",replace:!0})}),y.jsx(G,{path:"dashboard",element:y.jsx(qh,{})}),y.jsx(G,{path:"news",element:y.jsx(bh,{})}),y.jsx(G,{path:"inquiries",element:y.jsx(em,{})}),y.jsx(G,{path:"recruit",element:y.jsx(tm,{})}),y.jsx(G,{path:"settings",element:y.jsx(nm,{})})]}),y.jsx(G,{path:"*",element:y.jsx(xa,{to:"/admin/login",replace:!0})})]})}):y.jsx(rm,{children:y.jsxs(Ea,{children:[y.jsx(G,{path:"/",element:y.jsx($h,{})}),y.jsx(G,{path:"/solution/guardia",element:y.jsx(Bh,{})}),y.jsx(G,{path:"/solution/*",element:y.jsx(Vh,{})}),y.jsx(G,{path:"/company/*",element:y.jsx(Wh,{})}),y.jsx(G,{path:"/business/*",element:y.jsx(Hh,{})}),y.jsx(G,{path:"/support/contact",element:y.jsx(Qh,{})}),y.jsx(G,{path:"/support/*",element:y.jsx(Kh,{})}),y.jsx(G,{path:"/recruit/*",element:y.jsx(Gh,{})}),y.jsx(G,{path:"/news/*",element:y.jsx(Yh,{})}),y.jsx(G,{path:"*",element:y.jsx(Xh,{})})]})})}fo.createRoot(document.getElementById("root")).render(y.jsx(Ua.StrictMode,{children:y.jsx(Rh,{children:y.jsx(lm,{})})}));export{De as L,im as N,om as O,Ua as R,G as a,Ea as b,Gc as c,y as j,g as r,_t as u}; diff --git a/backend/src/main/resources/static/assets/index-DcNlVx-A.js b/backend/src/main/resources/static/assets/index-DcNlVx-A.js new file mode 100644 index 00000000..9cf4beb5 --- /dev/null +++ b/backend/src/main/resources/static/assets/index-DcNlVx-A.js @@ -0,0 +1,9 @@ +function tt(e,t){return function(){return e.apply(t,arguments)}}const{toString:_t}=Object.prototype,{getPrototypeOf:de}=Object,{iterator:pe,toStringTag:nt}=Symbol,he=(e=>t=>{const n=_t.call(t);return e[n]||(e[n]=n.slice(8,-1).toLowerCase())})(Object.create(null)),L=e=>(e=e.toLowerCase(),t=>he(t)===e),me=e=>t=>typeof t===e,{isArray:v}=Array,K=me("undefined");function Z(e){return e!==null&&!K(e)&&e.constructor!==null&&!K(e.constructor)&&C(e.constructor.isBuffer)&&e.constructor.isBuffer(e)}const rt=L("ArrayBuffer");function Tt(e){let t;return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?t=ArrayBuffer.isView(e):t=e&&e.buffer&&rt(e.buffer),t}const xt=me("string"),C=me("function"),st=me("number"),ee=e=>e!==null&&typeof e=="object",Ct=e=>e===!0||e===!1,ce=e=>{if(he(e)!=="object")return!1;const t=de(e);return(t===null||t===Object.prototype||Object.getPrototypeOf(t)===null)&&!(nt in e)&&!(pe in e)},Nt=e=>{if(!ee(e)||Z(e))return!1;try{return Object.keys(e).length===0&&Object.getPrototypeOf(e)===Object.prototype}catch{return!1}},Pt=L("Date"),Dt=L("File"),Lt=e=>!!(e&&typeof e.uri<"u"),Ft=e=>e&&typeof e.getParts<"u",Ut=L("Blob"),Bt=L("FileList"),kt=e=>ee(e)&&C(e.pipe);function jt(){return typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{}}const Me=jt(),ze=typeof Me.FormData<"u"?Me.FormData:void 0,qt=e=>{if(!e)return!1;if(ze&&e instanceof ze)return!0;const t=de(e);if(!t||t===Object.prototype||!C(e.append))return!1;const n=he(e);return n==="formdata"||n==="object"&&C(e.toString)&&e.toString()==="[object FormData]"},It=L("URLSearchParams"),[Ht,Mt,zt,$t]=["ReadableStream","Request","Response","Headers"].map(L),Vt=e=>e.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"");function te(e,t,{allOwnKeys:n=!1}={}){if(e===null||typeof e>"u")return;let r,s;if(typeof e!="object"&&(e=[e]),v(e))for(r=0,s=e.length;r0;)if(s=n[r],t===s.toLowerCase())return s;return null}const z=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:global,it=e=>!K(e)&&e!==z;function _e(...e){const{caseless:t,skipUndefined:n}=it(this)&&this||{},r={},s=(o,i)=>{if(i==="__proto__"||i==="constructor"||i==="prototype")return;const c=t&&ot(r,i)||i,l=Te(r,c)?r[c]:void 0;ce(l)&&ce(o)?r[c]=_e(l,o):ce(o)?r[c]=_e({},o):v(o)?r[c]=o.slice():(!n||!K(o))&&(r[c]=o)};for(let o=0,i=e.length;o(te(t,(s,o)=>{n&&C(s)?Object.defineProperty(e,o,{__proto__:null,value:tt(s,n),writable:!0,enumerable:!0,configurable:!0}):Object.defineProperty(e,o,{__proto__:null,value:s,writable:!0,enumerable:!0,configurable:!0})},{allOwnKeys:r}),e),Wt=e=>(e.charCodeAt(0)===65279&&(e=e.slice(1)),e),Kt=(e,t,n,r)=>{e.prototype=Object.create(t.prototype,r),Object.defineProperty(e.prototype,"constructor",{__proto__:null,value:e,writable:!0,enumerable:!1,configurable:!0}),Object.defineProperty(e,"super",{__proto__:null,value:t.prototype}),n&&Object.assign(e.prototype,n)},vt=(e,t,n,r)=>{let s,o,i;const c={};if(t=t||{},e==null)return t;do{for(s=Object.getOwnPropertyNames(e),o=s.length;o-- >0;)i=s[o],(!r||r(i,e,t))&&!c[i]&&(t[i]=e[i],c[i]=!0);e=n!==!1&&de(e)}while(e&&(!n||n(e,t))&&e!==Object.prototype);return t},Xt=(e,t,n)=>{e=String(e),(n===void 0||n>e.length)&&(n=e.length),n-=t.length;const r=e.indexOf(t,n);return r!==-1&&r===n},Gt=e=>{if(!e)return null;if(v(e))return e;let t=e.length;if(!st(t))return null;const n=new Array(t);for(;t-- >0;)n[t]=e[t];return n},Qt=(e=>t=>e&&t instanceof e)(typeof Uint8Array<"u"&&de(Uint8Array)),Yt=(e,t)=>{const r=(e&&e[pe]).call(e);let s;for(;(s=r.next())&&!s.done;){const o=s.value;t.call(e,o[0],o[1])}},Zt=(e,t)=>{let n;const r=[];for(;(n=e.exec(t))!==null;)r.push(n);return r},en=L("HTMLFormElement"),tn=e=>e.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,function(n,r,s){return r.toUpperCase()+s}),Te=(({hasOwnProperty:e})=>(t,n)=>e.call(t,n))(Object.prototype),nn=L("RegExp"),at=(e,t)=>{const n=Object.getOwnPropertyDescriptors(e),r={};te(n,(s,o)=>{let i;(i=t(s,o,e))!==!1&&(r[o]=i||s)}),Object.defineProperties(e,r)},rn=e=>{at(e,(t,n)=>{if(C(e)&&["arguments","caller","callee"].includes(n))return!1;const r=e[n];if(C(r)){if(t.enumerable=!1,"writable"in t){t.writable=!1;return}t.set||(t.set=()=>{throw Error("Can not rewrite read-only method '"+n+"'")})}})},sn=(e,t)=>{const n={},r=s=>{s.forEach(o=>{n[o]=!0})};return v(e)?r(e):r(String(e).split(t)),n},on=()=>{},an=(e,t)=>e!=null&&Number.isFinite(e=+e)?e:t;function cn(e){return!!(e&&C(e.append)&&e[nt]==="FormData"&&e[pe])}const ln=e=>{const t=new WeakSet,n=r=>{if(ee(r)){if(t.has(r))return;if(Z(r))return r;if(!("toJSON"in r)){t.add(r);const s=v(r)?[]:{};return te(r,(o,i)=>{const c=n(o);!K(c)&&(s[i]=c)}),t.delete(r),s}}return r};return n(e)},un=L("AsyncFunction"),fn=e=>e&&(ee(e)||C(e))&&C(e.then)&&C(e.catch),ct=((e,t)=>e?setImmediate:t?((n,r)=>(z.addEventListener("message",({source:s,data:o})=>{s===z&&o===n&&r.length&&r.shift()()},!1),s=>{r.push(s),z.postMessage(n,"*")}))(`axios@${Math.random()}`,[]):n=>setTimeout(n))(typeof setImmediate=="function",C(z.postMessage)),dn=typeof queueMicrotask<"u"?queueMicrotask.bind(z):typeof process<"u"&&process.nextTick||ct,pn=e=>e!=null&&C(e[pe]),a={isArray:v,isArrayBuffer:rt,isBuffer:Z,isFormData:qt,isArrayBufferView:Tt,isString:xt,isNumber:st,isBoolean:Ct,isObject:ee,isPlainObject:ce,isEmptyObject:Nt,isReadableStream:Ht,isRequest:Mt,isResponse:zt,isHeaders:$t,isUndefined:K,isDate:Pt,isFile:Dt,isReactNativeBlob:Lt,isReactNative:Ft,isBlob:Ut,isRegExp:nn,isFunction:C,isStream:kt,isURLSearchParams:It,isTypedArray:Qt,isFileList:Bt,forEach:te,merge:_e,extend:Jt,trim:Vt,stripBOM:Wt,inherits:Kt,toFlatObject:vt,kindOf:he,kindOfTest:L,endsWith:Xt,toArray:Gt,forEachEntry:Yt,matchAll:Zt,isHTMLForm:en,hasOwnProperty:Te,hasOwnProp:Te,reduceDescriptors:at,freezeMethods:rn,toObjectSet:sn,toCamelCase:tn,noop:on,toFiniteNumber:an,findKey:ot,global:z,isContextDefined:it,isSpecCompliantForm:cn,toJSONObject:ln,isAsyncFn:un,isThenable:fn,setImmediate:ct,asap:dn,isIterable:pn},hn=a.toObjectSet(["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"]),mn=e=>{const t={};let n,r,s;return e&&e.split(` +`).forEach(function(i){s=i.indexOf(":"),n=i.substring(0,s).trim().toLowerCase(),r=i.substring(s+1).trim(),!(!n||t[n]&&hn[n])&&(n==="set-cookie"?t[n]?t[n].push(r):t[n]=[r]:t[n]=t[n]?t[n]+", "+r:r)}),t};function yn(e){let t=0,n=e.length;for(;tt;){const r=e.charCodeAt(n-1);if(r!==9&&r!==32)break;n-=1}return t===0&&n===e.length?e:e.slice(t,n)}const bn=new RegExp("[\\u0000-\\u0008\\u000a-\\u001f\\u007f]+","g"),wn=new RegExp("[^\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+","g");function Pe(e,t){return a.isArray(e)?e.map(n=>Pe(n,t)):yn(String(e).replace(t,""))}const En=e=>Pe(e,bn),Rn=e=>Pe(e,wn);function lt(e){const t=Object.create(null);return a.forEach(e.toJSON(),(n,r)=>{t[r]=Rn(n)}),t}const $e=Symbol("internals");function Y(e){return e&&String(e).trim().toLowerCase()}function le(e){return e===!1||e==null?e:a.isArray(e)?e.map(le):En(String(e))}function gn(e){const t=Object.create(null),n=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let r;for(;r=n.exec(e);)t[r[1]]=r[2];return t}const On=e=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(e.trim());function ge(e,t,n,r,s){if(a.isFunction(r))return r.call(this,t,n);if(s&&(t=n),!!a.isString(t)){if(a.isString(r))return t.indexOf(r)!==-1;if(a.isRegExp(r))return r.test(t)}}function Sn(e){return e.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(t,n,r)=>n.toUpperCase()+r)}function An(e,t){const n=a.toCamelCase(" "+t);["get","set","has"].forEach(r=>{Object.defineProperty(e,r+n,{__proto__:null,value:function(s,o,i){return this[r].call(this,t,s,o,i)},configurable:!0})})}let x=class{constructor(t){t&&this.set(t)}set(t,n,r){const s=this;function o(c,l,f){const u=Y(l);if(!u)throw new Error("header name must be a non-empty string");const y=a.findKey(s,u);(!y||s[y]===void 0||f===!0||f===void 0&&s[y]!==!1)&&(s[y||l]=le(c))}const i=(c,l)=>a.forEach(c,(f,u)=>o(f,u,l));if(a.isPlainObject(t)||t instanceof this.constructor)i(t,n);else if(a.isString(t)&&(t=t.trim())&&!On(t))i(mn(t),n);else if(a.isObject(t)&&a.isIterable(t)){let c={},l,f;for(const u of t){if(!a.isArray(u))throw TypeError("Object iterator must return a key-value pair");c[f=u[0]]=(l=c[f])?a.isArray(l)?[...l,u[1]]:[l,u[1]]:u[1]}i(c,n)}else t!=null&&o(n,t,r);return this}get(t,n){if(t=Y(t),t){const r=a.findKey(this,t);if(r){const s=this[r];if(!n)return s;if(n===!0)return gn(s);if(a.isFunction(n))return n.call(this,s,r);if(a.isRegExp(n))return n.exec(s);throw new TypeError("parser must be boolean|regexp|function")}}}has(t,n){if(t=Y(t),t){const r=a.findKey(this,t);return!!(r&&this[r]!==void 0&&(!n||ge(this,this[r],r,n)))}return!1}delete(t,n){const r=this;let s=!1;function o(i){if(i=Y(i),i){const c=a.findKey(r,i);c&&(!n||ge(r,r[c],c,n))&&(delete r[c],s=!0)}}return a.isArray(t)?t.forEach(o):o(t),s}clear(t){const n=Object.keys(this);let r=n.length,s=!1;for(;r--;){const o=n[r];(!t||ge(this,this[o],o,t,!0))&&(delete this[o],s=!0)}return s}normalize(t){const n=this,r={};return a.forEach(this,(s,o)=>{const i=a.findKey(r,o);if(i){n[i]=le(s),delete n[o];return}const c=t?Sn(o):String(o).trim();c!==o&&delete n[o],n[c]=le(s),r[c]=!0}),this}concat(...t){return this.constructor.concat(this,...t)}toJSON(t){const n=Object.create(null);return a.forEach(this,(r,s)=>{r!=null&&r!==!1&&(n[s]=t&&a.isArray(r)?r.join(", "):r)}),n}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([t,n])=>t+": "+n).join(` +`)}getSetCookie(){return this.get("set-cookie")||[]}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(t){return t instanceof this?t:new this(t)}static concat(t,...n){const r=new this(t);return n.forEach(s=>r.set(s)),r}static accessor(t){const r=(this[$e]=this[$e]={accessors:{}}).accessors,s=this.prototype;function o(i){const c=Y(i);r[c]||(An(s,i),r[c]=!0)}return a.isArray(t)?t.forEach(o):o(t),this}};x.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);a.reduceDescriptors(x.prototype,({value:e},t)=>{let n=t[0].toUpperCase()+t.slice(1);return{get:()=>e,set(r){this[n]=r}}});a.freezeMethods(x);const _n="[REDACTED ****]";function Tn(e){if(a.hasOwnProp(e,"toJSON"))return!0;let t=Object.getPrototypeOf(e);for(;t&&t!==Object.prototype;){if(a.hasOwnProp(t,"toJSON"))return!0;t=Object.getPrototypeOf(t)}return!1}function xn(e,t){const n=new Set(t.map(o=>String(o).toLowerCase())),r=[],s=o=>{if(o===null||typeof o!="object"||a.isBuffer(o))return o;if(r.indexOf(o)!==-1)return;o instanceof x&&(o=o.toJSON()),r.push(o);let i;if(a.isArray(o))i=[],o.forEach((c,l)=>{const f=s(c);a.isUndefined(f)||(i[l]=f)});else{if(!a.isPlainObject(o)&&Tn(o))return r.pop(),o;i=Object.create(null);for(const[c,l]of Object.entries(o)){const f=n.has(c.toLowerCase())?_n:s(l);a.isUndefined(f)||(i[c]=f)}}return r.pop(),i};return s(e)}let p=class ut extends Error{static from(t,n,r,s,o,i){const c=new ut(t.message,n||t.code,r,s,o);return c.cause=t,c.name=t.name,t.status!=null&&c.status==null&&(c.status=t.status),i&&Object.assign(c,i),c}constructor(t,n,r,s,o){super(t),Object.defineProperty(this,"message",{__proto__:null,value:t,enumerable:!0,writable:!0,configurable:!0}),this.name="AxiosError",this.isAxiosError=!0,n&&(this.code=n),r&&(this.config=r),s&&(this.request=s),o&&(this.response=o,this.status=o.status)}toJSON(){const t=this.config,n=t&&a.hasOwnProp(t,"redact")?t.redact:void 0,r=a.isArray(n)&&n.length>0?xn(t,n):a.toJSONObject(t);return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:r,code:this.code,status:this.status}}};p.ERR_BAD_OPTION_VALUE="ERR_BAD_OPTION_VALUE";p.ERR_BAD_OPTION="ERR_BAD_OPTION";p.ECONNABORTED="ECONNABORTED";p.ETIMEDOUT="ETIMEDOUT";p.ECONNREFUSED="ECONNREFUSED";p.ERR_NETWORK="ERR_NETWORK";p.ERR_FR_TOO_MANY_REDIRECTS="ERR_FR_TOO_MANY_REDIRECTS";p.ERR_DEPRECATED="ERR_DEPRECATED";p.ERR_BAD_RESPONSE="ERR_BAD_RESPONSE";p.ERR_BAD_REQUEST="ERR_BAD_REQUEST";p.ERR_CANCELED="ERR_CANCELED";p.ERR_NOT_SUPPORT="ERR_NOT_SUPPORT";p.ERR_INVALID_URL="ERR_INVALID_URL";p.ERR_FORM_DATA_DEPTH_EXCEEDED="ERR_FORM_DATA_DEPTH_EXCEEDED";const Cn=null;function xe(e){return a.isPlainObject(e)||a.isArray(e)}function ft(e){return a.endsWith(e,"[]")?e.slice(0,-2):e}function Oe(e,t,n){return e?e.concat(t).map(function(s,o){return s=ft(s),!n&&o?"["+s+"]":s}).join(n?".":""):t}function Nn(e){return a.isArray(e)&&!e.some(xe)}const Pn=a.toFlatObject(a,{},null,function(t){return/^is[A-Z]/.test(t)});function ye(e,t,n){if(!a.isObject(e))throw new TypeError("target must be an object");t=t||new FormData,n=a.toFlatObject(n,{metaTokens:!0,dots:!1,indexes:!1},!1,function(d,m){return!a.isUndefined(m[d])});const r=n.metaTokens,s=n.visitor||y,o=n.dots,i=n.indexes,c=n.Blob||typeof Blob<"u"&&Blob,l=n.maxDepth===void 0?100:n.maxDepth,f=c&&a.isSpecCompliantForm(t);if(!a.isFunction(s))throw new TypeError("visitor must be a function");function u(h){if(h===null)return"";if(a.isDate(h))return h.toISOString();if(a.isBoolean(h))return h.toString();if(!f&&a.isBlob(h))throw new p("Blob is not supported. Use a Buffer instead.");return a.isArrayBuffer(h)||a.isTypedArray(h)?f&&typeof Blob=="function"?new Blob([h]):Buffer.from(h):h}function y(h,d,m){let O=h;if(a.isReactNative(t)&&a.isReactNativeBlob(h))return t.append(Oe(m,d,o),u(h)),!1;if(h&&!m&&typeof h=="object"){if(a.endsWith(d,"{}"))d=r?d:d.slice(0,-2),h=JSON.stringify(h);else if(a.isArray(h)&&Nn(h)||(a.isFileList(h)||a.endsWith(d,"[]"))&&(O=a.toArray(h)))return d=ft(d),O.forEach(function(R,N){!(a.isUndefined(R)||R===null)&&t.append(i===!0?Oe([d],N,o):i===null?d:d+"[]",u(R))}),!1}return xe(h)?!0:(t.append(Oe(m,d,o),u(h)),!1)}const E=[],b=Object.assign(Pn,{defaultVisitor:y,convertValue:u,isVisitable:xe});function w(h,d,m=0){if(!a.isUndefined(h)){if(m>l)throw new p("Object is too deeply nested ("+m+" levels). Max depth: "+l,p.ERR_FORM_DATA_DEPTH_EXCEEDED);if(E.indexOf(h)!==-1)throw Error("Circular reference detected in "+d.join("."));E.push(h),a.forEach(h,function(g,R){(!(a.isUndefined(g)||g===null)&&s.call(t,g,a.isString(R)?R.trim():R,d,b))===!0&&w(g,d?d.concat(R):[R],m+1)}),E.pop()}}if(!a.isObject(e))throw new TypeError("data must be an object");return w(e),t}function Ve(e){const t={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+"};return encodeURIComponent(e).replace(/[!'()~]|%20/g,function(r){return t[r]})}function De(e,t){this._pairs=[],e&&ye(e,this,t)}const dt=De.prototype;dt.append=function(t,n){this._pairs.push([t,n])};dt.toString=function(t){const n=t?function(r){return t.call(this,r,Ve)}:Ve;return this._pairs.map(function(s){return n(s[0])+"="+n(s[1])},"").join("&")};function Dn(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+")}function pt(e,t,n){if(!t)return e;const r=n&&n.encode||Dn,s=a.isFunction(n)?{serialize:n}:n,o=s&&s.serialize;let i;if(o?i=o(t,s):i=a.isURLSearchParams(t)?t.toString():new De(t,s).toString(r),i){const c=e.indexOf("#");c!==-1&&(e=e.slice(0,c)),e+=(e.indexOf("?")===-1?"?":"&")+i}return e}class Je{constructor(){this.handlers=[]}use(t,n,r){return this.handlers.push({fulfilled:t,rejected:n,synchronous:r?r.synchronous:!1,runWhen:r?r.runWhen:null}),this.handlers.length-1}eject(t){this.handlers[t]&&(this.handlers[t]=null)}clear(){this.handlers&&(this.handlers=[])}forEach(t){a.forEach(this.handlers,function(r){r!==null&&t(r)})}}const Le={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1,legacyInterceptorReqResOrdering:!0},Ln=typeof URLSearchParams<"u"?URLSearchParams:De,Fn=typeof FormData<"u"?FormData:null,Un=typeof Blob<"u"?Blob:null,Bn={isBrowser:!0,classes:{URLSearchParams:Ln,FormData:Fn,Blob:Un},protocols:["http","https","file","blob","url","data"]},Fe=typeof window<"u"&&typeof document<"u",Ce=typeof navigator=="object"&&navigator||void 0,kn=Fe&&(!Ce||["ReactNative","NativeScript","NS"].indexOf(Ce.product)<0),jn=typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope&&typeof self.importScripts=="function",qn=Fe&&window.location.href||"http://localhost",In=Object.freeze(Object.defineProperty({__proto__:null,hasBrowserEnv:Fe,hasStandardBrowserEnv:kn,hasStandardBrowserWebWorkerEnv:jn,navigator:Ce,origin:qn},Symbol.toStringTag,{value:"Module"})),T={...In,...Bn};function Hn(e,t){return ye(e,new T.classes.URLSearchParams,{visitor:function(n,r,s,o){return T.isNode&&a.isBuffer(n)?(this.append(r,n.toString("base64")),!1):o.defaultVisitor.apply(this,arguments)},...t})}function Mn(e){return a.matchAll(/\w+|\[(\w*)]/g,e).map(t=>t[0]==="[]"?"":t[1]||t[0])}function zn(e){const t={},n=Object.keys(e);let r;const s=n.length;let o;for(r=0;r=n.length;return i=!i&&a.isArray(s)?s.length:i,l?(a.hasOwnProp(s,i)?s[i]=a.isArray(s[i])?s[i].concat(r):[s[i],r]:s[i]=r,!c):((!a.hasOwnProp(s,i)||!a.isObject(s[i]))&&(s[i]=[]),t(n,r,s[i],o)&&a.isArray(s[i])&&(s[i]=zn(s[i])),!c)}if(a.isFormData(e)&&a.isFunction(e.entries)){const n={};return a.forEachEntry(e,(r,s)=>{t(Mn(r),s,n,0)}),n}return null}const W=(e,t)=>e!=null&&a.hasOwnProp(e,t)?e[t]:void 0;function $n(e,t,n){if(a.isString(e))try{return(t||JSON.parse)(e),a.trim(e)}catch(r){if(r.name!=="SyntaxError")throw r}return(n||JSON.stringify)(e)}const ne={transitional:Le,adapter:["xhr","http","fetch"],transformRequest:[function(t,n){const r=n.getContentType()||"",s=r.indexOf("application/json")>-1,o=a.isObject(t);if(o&&a.isHTMLForm(t)&&(t=new FormData(t)),a.isFormData(t))return s?JSON.stringify(ht(t)):t;if(a.isArrayBuffer(t)||a.isBuffer(t)||a.isStream(t)||a.isFile(t)||a.isBlob(t)||a.isReadableStream(t))return t;if(a.isArrayBufferView(t))return t.buffer;if(a.isURLSearchParams(t))return n.setContentType("application/x-www-form-urlencoded;charset=utf-8",!1),t.toString();let c;if(o){const l=W(this,"formSerializer");if(r.indexOf("application/x-www-form-urlencoded")>-1)return Hn(t,l).toString();if((c=a.isFileList(t))||r.indexOf("multipart/form-data")>-1){const f=W(this,"env"),u=f&&f.FormData;return ye(c?{"files[]":t}:t,u&&new u,l)}}return o||s?(n.setContentType("application/json",!1),$n(t)):t}],transformResponse:[function(t){const n=W(this,"transitional")||ne.transitional,r=n&&n.forcedJSONParsing,s=W(this,"responseType"),o=s==="json";if(a.isResponse(t)||a.isReadableStream(t))return t;if(t&&a.isString(t)&&(r&&!s||o)){const c=!(n&&n.silentJSONParsing)&&o;try{return JSON.parse(t,W(this,"parseReviver"))}catch(l){if(c)throw l.name==="SyntaxError"?p.from(l,p.ERR_BAD_RESPONSE,this,null,W(this,"response")):l}}return t}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:T.classes.FormData,Blob:T.classes.Blob},validateStatus:function(t){return t>=200&&t<300},headers:{common:{Accept:"application/json, text/plain, */*","Content-Type":void 0}}};a.forEach(["delete","get","head","post","put","patch","query"],e=>{ne.headers[e]={}});function Se(e,t){const n=this||ne,r=t||n,s=x.from(r.headers);let o=r.data;return a.forEach(e,function(c){o=c.call(n,o,s.normalize(),t?t.status:void 0)}),s.normalize(),o}function mt(e){return!!(e&&e.__CANCEL__)}let re=class extends p{constructor(t,n,r){super(t??"canceled",p.ERR_CANCELED,n,r),this.name="CanceledError",this.__CANCEL__=!0}};function yt(e,t,n){const r=n.config.validateStatus;!n.status||!r||r(n.status)?e(n):t(new p("Request failed with status code "+n.status,n.status>=400&&n.status<500?p.ERR_BAD_REQUEST:p.ERR_BAD_RESPONSE,n.config,n.request,n))}function Vn(e){const t=/^([-+\w]{1,25}):(?:\/\/)?/.exec(e);return t&&t[1]||""}function Jn(e,t){e=e||10;const n=new Array(e),r=new Array(e);let s=0,o=0,i;return t=t!==void 0?t:1e3,function(l){const f=Date.now(),u=r[o];i||(i=f),n[s]=l,r[s]=f;let y=o,E=0;for(;y!==s;)E+=n[y++],y=y%e;if(s=(s+1)%e,s===o&&(o=(o+1)%e),f-i{n=u,s=null,o&&(clearTimeout(o),o=null),e(...f)};return[(...f)=>{const u=Date.now(),y=u-n;y>=r?i(f,u):(s=f,o||(o=setTimeout(()=>{o=null,i(s)},r-y)))},()=>s&&i(s)]}const fe=(e,t,n=3)=>{let r=0;const s=Jn(50,250);return Wn(o=>{if(!o||typeof o.loaded!="number")return;const i=o.loaded,c=o.lengthComputable?o.total:void 0,l=c!=null?Math.min(i,c):i,f=Math.max(0,l-r),u=s(f);r=Math.max(r,l);const y={loaded:l,total:c,progress:c?l/c:void 0,bytes:f,rate:u||void 0,estimated:u&&c?(c-l)/u:void 0,event:o,lengthComputable:c!=null,[t?"download":"upload"]:!0};e(y)},n)},We=(e,t)=>{const n=e!=null;return[r=>t[0]({lengthComputable:n,total:e,loaded:r}),t[1]]},Ke=e=>(...t)=>a.asap(()=>e(...t)),Kn=T.hasStandardBrowserEnv?((e,t)=>n=>(n=new URL(n,T.origin),e.protocol===n.protocol&&e.host===n.host&&(t||e.port===n.port)))(new URL(T.origin),T.navigator&&/(msie|trident)/i.test(T.navigator.userAgent)):()=>!0,vn=T.hasStandardBrowserEnv?{write(e,t,n,r,s,o,i){if(typeof document>"u")return;const c=[`${e}=${encodeURIComponent(t)}`];a.isNumber(n)&&c.push(`expires=${new Date(n).toUTCString()}`),a.isString(r)&&c.push(`path=${r}`),a.isString(s)&&c.push(`domain=${s}`),o===!0&&c.push("secure"),a.isString(i)&&c.push(`SameSite=${i}`),document.cookie=c.join("; ")},read(e){if(typeof document>"u")return null;const t=document.cookie.split(";");for(let n=0;ne instanceof x?{...e}:e;function V(e,t){t=t||{};const n=Object.create(null);Object.defineProperty(n,"hasOwnProperty",{__proto__:null,value:Object.prototype.hasOwnProperty,enumerable:!1,writable:!0,configurable:!0});function r(f,u,y,E){return a.isPlainObject(f)&&a.isPlainObject(u)?a.merge.call({caseless:E},f,u):a.isPlainObject(u)?a.merge({},u):a.isArray(u)?u.slice():u}function s(f,u,y,E){if(a.isUndefined(u)){if(!a.isUndefined(f))return r(void 0,f,y,E)}else return r(f,u,y,E)}function o(f,u){if(!a.isUndefined(u))return r(void 0,u)}function i(f,u){if(a.isUndefined(u)){if(!a.isUndefined(f))return r(void 0,f)}else return r(void 0,u)}function c(f,u,y){if(a.hasOwnProp(t,y))return r(f,u);if(a.hasOwnProp(e,y))return r(void 0,f)}const l={url:o,method:o,data:o,baseURL:i,transformRequest:i,transformResponse:i,paramsSerializer:i,timeout:i,timeoutMessage:i,withCredentials:i,withXSRFToken:i,adapter:i,responseType:i,xsrfCookieName:i,xsrfHeaderName:i,onUploadProgress:i,onDownloadProgress:i,decompress:i,maxContentLength:i,maxBodyLength:i,beforeRedirect:i,transport:i,httpAgent:i,httpsAgent:i,cancelToken:i,socketPath:i,allowedSocketPaths:i,responseEncoding:i,validateStatus:c,headers:(f,u,y)=>s(ve(f),ve(u),y,!0)};return a.forEach(Object.keys({...e,...t}),function(u){if(u==="__proto__"||u==="constructor"||u==="prototype")return;const y=a.hasOwnProp(l,u)?l[u]:s,E=a.hasOwnProp(e,u)?e[u]:void 0,b=a.hasOwnProp(t,u)?t[u]:void 0,w=y(E,b,u);a.isUndefined(w)&&y!==c||(n[u]=w)}),n}const Qn=["content-type","content-length"];function Yn(e,t,n){if(n!=="content-only"){e.set(t);return}Object.entries(t).forEach(([r,s])=>{Qn.includes(r.toLowerCase())&&e.set(r,s)})}const Zn=e=>encodeURIComponent(e).replace(/%([0-9A-F]{2})/gi,(t,n)=>String.fromCharCode(parseInt(n,16))),wt=e=>{const t=V({},e),n=E=>a.hasOwnProp(t,E)?t[E]:void 0,r=n("data");let s=n("withXSRFToken");const o=n("xsrfHeaderName"),i=n("xsrfCookieName");let c=n("headers");const l=n("auth"),f=n("baseURL"),u=n("allowAbsoluteUrls"),y=n("url");if(t.headers=c=x.from(c),t.url=pt(bt(f,y,u),e.params,e.paramsSerializer),l&&c.set("Authorization","Basic "+btoa((l.username||"")+":"+(l.password?Zn(l.password):""))),a.isFormData(r)&&(T.hasStandardBrowserEnv||T.hasStandardBrowserWebWorkerEnv?c.setContentType(void 0):a.isFunction(r.getHeaders)&&Yn(c,r.getHeaders(),n("formDataHeaderPolicy"))),T.hasStandardBrowserEnv&&(a.isFunction(s)&&(s=s(t)),s===!0||s==null&&Kn(t.url))){const b=o&&i&&vn.read(i);b&&c.set(o,b)}return t},er=typeof XMLHttpRequest<"u",tr=er&&function(e){return new Promise(function(n,r){const s=wt(e);let o=s.data;const i=x.from(s.headers).normalize();let{responseType:c,onUploadProgress:l,onDownloadProgress:f}=s,u,y,E,b,w;function h(){b&&b(),w&&w(),s.cancelToken&&s.cancelToken.unsubscribe(u),s.signal&&s.signal.removeEventListener("abort",u)}let d=new XMLHttpRequest;d.open(s.method.toUpperCase(),s.url,!0),d.timeout=s.timeout;function m(){if(!d)return;const g=x.from("getAllResponseHeaders"in d&&d.getAllResponseHeaders()),N={data:!c||c==="text"||c==="json"?d.responseText:d.response,status:d.status,statusText:d.statusText,headers:g,config:e,request:d};yt(function(X){n(X),h()},function(X){r(X),h()},N),d=null}"onloadend"in d?d.onloadend=m:d.onreadystatechange=function(){!d||d.readyState!==4||d.status===0&&!(d.responseURL&&d.responseURL.startsWith("file:"))||setTimeout(m)},d.onabort=function(){d&&(r(new p("Request aborted",p.ECONNABORTED,e,d)),h(),d=null)},d.onerror=function(R){const N=R&&R.message?R.message:"Network Error",I=new p(N,p.ERR_NETWORK,e,d);I.event=R||null,r(I),h(),d=null},d.ontimeout=function(){let R=s.timeout?"timeout of "+s.timeout+"ms exceeded":"timeout exceeded";const N=s.transitional||Le;s.timeoutErrorMessage&&(R=s.timeoutErrorMessage),r(new p(R,N.clarifyTimeoutError?p.ETIMEDOUT:p.ECONNABORTED,e,d)),h(),d=null},o===void 0&&i.setContentType(null),"setRequestHeader"in d&&a.forEach(lt(i),function(R,N){d.setRequestHeader(N,R)}),a.isUndefined(s.withCredentials)||(d.withCredentials=!!s.withCredentials),c&&c!=="json"&&(d.responseType=s.responseType),f&&([E,w]=fe(f,!0),d.addEventListener("progress",E)),l&&d.upload&&([y,b]=fe(l),d.upload.addEventListener("progress",y),d.upload.addEventListener("loadend",b)),(s.cancelToken||s.signal)&&(u=g=>{d&&(r(!g||g.type?new re(null,e,d):g),d.abort(),h(),d=null)},s.cancelToken&&s.cancelToken.subscribe(u),s.signal&&(s.signal.aborted?u():s.signal.addEventListener("abort",u)));const O=Vn(s.url);if(O&&!T.protocols.includes(O)){r(new p("Unsupported protocol "+O+":",p.ERR_BAD_REQUEST,e));return}d.send(o||null)})},nr=(e,t)=>{if(e=e?e.filter(Boolean):[],!t&&!e.length)return;const n=new AbortController;let r=!1;const s=function(l){if(!r){r=!0,i();const f=l instanceof Error?l:this.reason;n.abort(f instanceof p?f:new re(f instanceof Error?f.message:f))}};let o=t&&setTimeout(()=>{o=null,s(new p(`timeout of ${t}ms exceeded`,p.ETIMEDOUT))},t);const i=()=>{e&&(o&&clearTimeout(o),o=null,e.forEach(l=>{l.unsubscribe?l.unsubscribe(s):l.removeEventListener("abort",s)}),e=null)};e.forEach(l=>l.addEventListener("abort",s));const{signal:c}=n;return c.unsubscribe=()=>a.asap(i),c},rr=function*(e,t){let n=e.byteLength;if(n{const s=sr(e,t);let o=0,i,c=l=>{i||(i=!0,r&&r(l))};return new ReadableStream({async pull(l){try{const{done:f,value:u}=await s.next();if(f){c(),l.close();return}let y=u.byteLength;if(n){let E=o+=y;n(E)}l.enqueue(new Uint8Array(u))}catch(f){throw c(f),f}},cancel(l){return c(l),s.return()}},{highWaterMark:2})};function ir(e){if(!e||typeof e!="string"||!e.startsWith("data:"))return 0;const t=e.indexOf(",");if(t<0)return 0;const n=e.slice(5,t),r=e.slice(t+1);if(/;base64/i.test(n)){let i=r.length;const c=r.length;for(let b=0;b=48&&w<=57||w>=65&&w<=70||w>=97&&w<=102)&&(h>=48&&h<=57||h>=65&&h<=70||h>=97&&h<=102)&&(i-=2,b+=2)}let l=0,f=c-1;const u=b=>b>=2&&r.charCodeAt(b-2)===37&&r.charCodeAt(b-1)===51&&(r.charCodeAt(b)===68||r.charCodeAt(b)===100);f>=0&&(r.charCodeAt(f)===61?(l++,f--):u(f)&&(l++,f-=3)),l===1&&f>=0&&(r.charCodeAt(f)===61||u(f))&&l++;const E=Math.floor(i/4)*3-(l||0);return E>0?E:0}if(typeof Buffer<"u"&&typeof Buffer.byteLength=="function")return Buffer.byteLength(r,"utf8");let o=0;for(let i=0,c=r.length;i=55296&&l<=56319&&i+1=56320&&f<=57343?(o+=4,i++):o+=3}else o+=3}return o}const Ue="1.16.1",Ge=64*1024,{isFunction:ae}=a,Qe=(e,...t)=>{try{return!!e(...t)}catch{return!1}},ar=e=>{const t=a.global!==void 0&&a.global!==null?a.global:globalThis,{ReadableStream:n,TextEncoder:r}=t;e=a.merge.call({skipUndefined:!0},{Request:t.Request,Response:t.Response},e);const{fetch:s,Request:o,Response:i}=e,c=s?ae(s):typeof fetch=="function",l=ae(o),f=ae(i);if(!c)return!1;const u=c&&ae(n),y=c&&(typeof r=="function"?(m=>O=>m.encode(O))(new r):async m=>new Uint8Array(await new o(m).arrayBuffer())),E=l&&u&&Qe(()=>{let m=!1;const O=new o(T.origin,{body:new n,method:"POST",get duplex(){return m=!0,"half"}}),g=O.headers.has("Content-Type");return O.body!=null&&O.body.cancel(),m&&!g}),b=f&&u&&Qe(()=>a.isReadableStream(new i("").body)),w={stream:b&&(m=>m.body)};c&&["text","arrayBuffer","blob","formData","stream"].forEach(m=>{!w[m]&&(w[m]=(O,g)=>{let R=O&&O[m];if(R)return R.call(O);throw new p(`Response type '${m}' is not supported`,p.ERR_NOT_SUPPORT,g)})});const h=async m=>{if(m==null)return 0;if(a.isBlob(m))return m.size;if(a.isSpecCompliantForm(m))return(await new o(T.origin,{method:"POST",body:m}).arrayBuffer()).byteLength;if(a.isArrayBufferView(m)||a.isArrayBuffer(m))return m.byteLength;if(a.isURLSearchParams(m)&&(m=m+""),a.isString(m))return(await y(m)).byteLength},d=async(m,O)=>{const g=a.toFiniteNumber(m.getContentLength());return g??h(O)};return async m=>{let{url:O,method:g,data:R,signal:N,cancelToken:I,timeout:X,onDownloadProgress:we,onUploadProgress:ke,responseType:k,headers:H,withCredentials:se="same-origin",fetchOptions:je,maxContentLength:F,maxBodyLength:Ee}=wt(m);const G=a.isNumber(F)&&F>-1,St=a.isNumber(Ee)&&Ee>-1;let qe=s||fetch;k=k?(k+"").toLowerCase():"text";let j=nr([N,I&&I.toAbortSignal()],X),P=null;const M=j&&j.unsubscribe&&(()=>{j.unsubscribe()});let Ie;try{if(G&&typeof O=="string"&&O.startsWith("data:")&&ir(O)>F)throw new p("maxContentLength size of "+F+" exceeded",p.ERR_BAD_RESPONSE,m,P);if(St&&g!=="get"&&g!=="head"){const S=await d(H,R);if(typeof S=="number"&&isFinite(S)&&S>Ee)throw new p("Request body larger than maxBodyLength limit",p.ERR_BAD_REQUEST,m,P)}if(ke&&E&&g!=="get"&&g!=="head"&&(Ie=await d(H,R))!==0){let S=new o(O,{method:"POST",body:R,duplex:"half"}),J;if(a.isFormData(R)&&(J=S.headers.get("content-type"))&&H.setContentType(J),S.body){const[oe,ie]=We(Ie,fe(Ke(ke)));R=Xe(S.body,Ge,oe,ie)}}a.isString(se)||(se=se?"include":"omit");const _=l&&"credentials"in o.prototype;if(a.isFormData(R)){const S=H.getContentType();S&&/^multipart\/form-data/i.test(S)&&!/boundary=/i.test(S)&&H.delete("content-type")}H.set("User-Agent","axios/"+Ue,!1);const q={...je,signal:j,method:g.toUpperCase(),headers:lt(H.normalize()),body:R,duplex:"half",credentials:_?se:void 0};P=l&&new o(O,q);let U=await(l?qe(P,je):qe(O,q));if(G){const S=a.toFiniteNumber(U.headers.get("content-length"));if(S!=null&&S>F)throw new p("maxContentLength size of "+F+" exceeded",p.ERR_BAD_RESPONSE,m,P)}const Re=b&&(k==="stream"||k==="response");if(b&&U.body&&(we||G||Re&&M)){const S={};["status","statusText","headers"].forEach(Q=>{S[Q]=U[Q]});const J=a.toFiniteNumber(U.headers.get("content-length")),[oe,ie]=we&&We(J,fe(Ke(we),!0))||[];let He=0;const At=Q=>{if(G&&(He=Q,He>F))throw new p("maxContentLength size of "+F+" exceeded",p.ERR_BAD_RESPONSE,m,P);oe&&oe(Q)};U=new i(Xe(U.body,Ge,At,()=>{ie&&ie(),M&&M()}),S)}k=k||"text";let B=await w[a.findKey(w,k)||"text"](U,m);if(G&&!b&&!Re){let S;if(B!=null&&(typeof B.byteLength=="number"?S=B.byteLength:typeof B.size=="number"?S=B.size:typeof B=="string"&&(S=typeof r=="function"?new r().encode(B).byteLength:B.length)),typeof S=="number"&&S>F)throw new p("maxContentLength size of "+F+" exceeded",p.ERR_BAD_RESPONSE,m,P)}return!Re&&M&&M(),await new Promise((S,J)=>{yt(S,J,{data:B,headers:x.from(U.headers),status:U.status,statusText:U.statusText,config:m,request:P})})}catch(_){if(M&&M(),j&&j.aborted&&j.reason instanceof p){const q=j.reason;throw q.config=m,P&&(q.request=P),_!==q&&(q.cause=_),q}throw _&&_.name==="TypeError"&&/Load failed|fetch/i.test(_.message)?Object.assign(new p("Network Error",p.ERR_NETWORK,m,P,_&&_.response),{cause:_.cause||_}):p.from(_,_&&_.code,m,P,_&&_.response)}}},cr=new Map,Et=e=>{let t=e&&e.env||{};const{fetch:n,Request:r,Response:s}=t,o=[r,s,n];let i=o.length,c=i,l,f,u=cr;for(;c--;)l=o[c],f=u.get(l),f===void 0&&u.set(l,f=c?new Map:ar(t)),u=f;return f};Et();const Be={http:Cn,xhr:tr,fetch:{get:Et}};a.forEach(Be,(e,t)=>{if(e){try{Object.defineProperty(e,"name",{__proto__:null,value:t})}catch{}Object.defineProperty(e,"adapterName",{__proto__:null,value:t})}});const Ye=e=>`- ${e}`,lr=e=>a.isFunction(e)||e===null||e===!1;function ur(e,t){e=a.isArray(e)?e:[e];const{length:n}=e;let r,s;const o={};for(let i=0;i`adapter ${l} `+(f===!1?"is not supported by the environment":"is not available in the build"));let c=n?i.length>1?`since : +`+i.map(Ye).join(` +`):" "+Ye(i[0]):"as no adapter specified";throw new p("There is no suitable adapter to dispatch the request "+c,"ERR_NOT_SUPPORT")}return s}const Rt={getAdapter:ur,adapters:Be};function Ae(e){if(e.cancelToken&&e.cancelToken.throwIfRequested(),e.signal&&e.signal.aborted)throw new re(null,e)}function Ze(e){return Ae(e),e.headers=x.from(e.headers),e.data=Se.call(e,e.transformRequest),["post","put","patch"].indexOf(e.method)!==-1&&e.headers.setContentType("application/x-www-form-urlencoded",!1),Rt.getAdapter(e.adapter||ne.adapter,e)(e).then(function(r){Ae(e),e.response=r;try{r.data=Se.call(e,e.transformResponse,r)}finally{delete e.response}return r.headers=x.from(r.headers),r},function(r){if(!mt(r)&&(Ae(e),r&&r.response)){e.response=r.response;try{r.response.data=Se.call(e,e.transformResponse,r.response)}finally{delete e.response}r.response.headers=x.from(r.response.headers)}return Promise.reject(r)})}const be={};["object","boolean","number","function","string","symbol"].forEach((e,t)=>{be[e]=function(r){return typeof r===e||"a"+(t<1?"n ":" ")+e}});const et={};be.transitional=function(t,n,r){function s(o,i){return"[Axios v"+Ue+"] Transitional option '"+o+"'"+i+(r?". "+r:"")}return(o,i,c)=>{if(t===!1)throw new p(s(i," has been removed"+(n?" in "+n:"")),p.ERR_DEPRECATED);return n&&!et[i]&&(et[i]=!0,console.warn(s(i," has been deprecated since v"+n+" and will be removed in the near future"))),t?t(o,i,c):!0}};be.spelling=function(t){return(n,r)=>(console.warn(`${r} is likely a misspelling of ${t}`),!0)};function fr(e,t,n){if(typeof e!="object")throw new p("options must be an object",p.ERR_BAD_OPTION_VALUE);const r=Object.keys(e);let s=r.length;for(;s-- >0;){const o=r[s],i=Object.prototype.hasOwnProperty.call(t,o)?t[o]:void 0;if(i){const c=e[o],l=c===void 0||i(c,o,e);if(l!==!0)throw new p("option "+o+" must be "+l,p.ERR_BAD_OPTION_VALUE);continue}if(n!==!0)throw new p("Unknown option "+o,p.ERR_BAD_OPTION)}}const ue={assertOptions:fr,validators:be},D=ue.validators;let $=class{constructor(t){this.defaults=t||{},this.interceptors={request:new Je,response:new Je}}async request(t,n){try{return await this._request(t,n)}catch(r){if(r instanceof Error){let s={};Error.captureStackTrace?Error.captureStackTrace(s):s=new Error;const o=(()=>{if(!s.stack)return"";const i=s.stack.indexOf(` +`);return i===-1?"":s.stack.slice(i+1)})();try{if(!r.stack)r.stack=o;else if(o){const i=o.indexOf(` +`),c=i===-1?-1:o.indexOf(` +`,i+1),l=c===-1?"":o.slice(c+1);String(r.stack).endsWith(l)||(r.stack+=` +`+o)}}catch{}}throw r}}_request(t,n){typeof t=="string"?(n=n||{},n.url=t):n=t||{},n=V(this.defaults,n);const{transitional:r,paramsSerializer:s,headers:o}=n;r!==void 0&&ue.assertOptions(r,{silentJSONParsing:D.transitional(D.boolean),forcedJSONParsing:D.transitional(D.boolean),clarifyTimeoutError:D.transitional(D.boolean),legacyInterceptorReqResOrdering:D.transitional(D.boolean)},!1),s!=null&&(a.isFunction(s)?n.paramsSerializer={serialize:s}:ue.assertOptions(s,{encode:D.function,serialize:D.function},!0)),n.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?n.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:n.allowAbsoluteUrls=!0),ue.assertOptions(n,{baseUrl:D.spelling("baseURL"),withXsrfToken:D.spelling("withXSRFToken")},!0),n.method=(n.method||this.defaults.method||"get").toLowerCase();let i=o&&a.merge(o.common,o[n.method]);o&&a.forEach(["delete","get","head","post","put","patch","query","common"],w=>{delete o[w]}),n.headers=x.concat(i,o);const c=[];let l=!0;this.interceptors.request.forEach(function(h){if(typeof h.runWhen=="function"&&h.runWhen(n)===!1)return;l=l&&h.synchronous;const d=n.transitional||Le;d&&d.legacyInterceptorReqResOrdering?c.unshift(h.fulfilled,h.rejected):c.push(h.fulfilled,h.rejected)});const f=[];this.interceptors.response.forEach(function(h){f.push(h.fulfilled,h.rejected)});let u,y=0,E;if(!l){const w=[Ze.bind(this),void 0];for(w.unshift(...c),w.push(...f),E=w.length,u=Promise.resolve(n);y{if(!r._listeners)return;let o=r._listeners.length;for(;o-- >0;)r._listeners[o](s);r._listeners=null}),this.promise.then=s=>{let o;const i=new Promise(c=>{r.subscribe(c),o=c}).then(s);return i.cancel=function(){r.unsubscribe(o)},i},t(function(o,i,c){r.reason||(r.reason=new re(o,i,c),n(r.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){if(this.reason){t(this.reason);return}this._listeners?this._listeners.push(t):this._listeners=[t]}unsubscribe(t){if(!this._listeners)return;const n=this._listeners.indexOf(t);n!==-1&&this._listeners.splice(n,1)}toAbortSignal(){const t=new AbortController,n=r=>{t.abort(r)};return this.subscribe(n),t.signal.unsubscribe=()=>this.unsubscribe(n),t.signal}static source(){let t;return{token:new gt(function(s){t=s}),cancel:t}}};function pr(e){return function(n){return e.apply(null,n)}}function hr(e){return a.isObject(e)&&e.isAxiosError===!0}const Ne={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(Ne).forEach(([e,t])=>{Ne[t]=e});function Ot(e){const t=new $(e),n=tt($.prototype.request,t);return a.extend(n,$.prototype,t,{allOwnKeys:!0}),a.extend(n,t,null,{allOwnKeys:!0}),n.create=function(s){return Ot(V(e,s))},n}const A=Ot(ne);A.Axios=$;A.CanceledError=re;A.CancelToken=dr;A.isCancel=mt;A.VERSION=Ue;A.toFormData=ye;A.AxiosError=p;A.Cancel=A.CanceledError;A.all=function(t){return Promise.all(t)};A.spread=pr;A.isAxiosError=hr;A.mergeConfig=V;A.AxiosHeaders=x;A.formToJSON=e=>ht(a.isHTMLForm(e)?new FormData(e):e);A.getAdapter=Rt.getAdapter;A.HttpStatusCode=Ne;A.default=A;const{Axios:wr,AxiosError:Er,CanceledError:Rr,isCancel:gr,CancelToken:Or,VERSION:Sr,all:Ar,Cancel:_r,isAxiosError:Tr,spread:xr,toFormData:Cr,AxiosHeaders:Nr,HttpStatusCode:Pr,formToJSON:Dr,getAdapter:Lr,mergeConfig:Fr,create:Ur}=A;export{A as a}; diff --git a/backend/src/main/resources/static/assets/index-Dk81znn6.css b/backend/src/main/resources/static/assets/index-Dk81znn6.css new file mode 100644 index 00000000..698c3d54 --- /dev/null +++ b/backend/src/main/resources/static/assets/index-Dk81znn6.css @@ -0,0 +1 @@ +.skip-link{position:absolute;top:-60px;left:0;z-index:9999;background:var(--primary);color:#fff;padding:10px 20px;border-radius:0 0 8px;transition:top .2s}.skip-link:focus{top:0}.header{position:fixed;top:0;left:0;right:0;z-index:1000;height:var(--header-h);background:#1a1a2ef5;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);border-bottom:1px solid rgba(255,255,255,.08);transition:all var(--mid) var(--ease)}.header.scrolled{background:#1a1a2efc;box-shadow:0 4px 24px #0000004d}.header-inner{display:flex;align-items:center;gap:32px;height:100%}.logo{display:flex;align-items:center;gap:10px;flex-shrink:0}.logo img{height:40px;width:auto;filter:brightness(0) invert(1)}.logo-text{color:#fff;font-size:20px;font-weight:700}.logo-text strong{color:var(--accent)}.nav-desktop{display:flex;align-items:center;gap:4px;margin-left:24px;flex:1}.nav-item{position:relative}.nav-trigger{height:var(--header-h);padding:0 16px;color:#ffffffd9;font-size:15px;font-weight:500;transition:color var(--fast);display:flex;align-items:center}.nav-trigger:hover,.nav-item.active .nav-trigger{color:#fff}.nav-item.active .nav-trigger{border-bottom:2px solid var(--accent)}.dropdown{position:absolute;top:calc(var(--header-h) - 2px);left:0;min-width:180px;background:#fff;border-radius:0 0 var(--radius) var(--radius);box-shadow:var(--shadow-lg);border-top:3px solid var(--primary);padding:8px 0;animation:fadeDown .18s ease}@keyframes fadeDown{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.dropdown-item{display:flex;align-items:center;gap:8px;padding:10px 20px;font-size:14px;color:var(--gray-700);transition:all var(--fast)}.dropdown-item:hover,.dropdown-item.current{background:var(--primary-light);color:var(--primary)}.header-cta{margin-left:auto;flex-shrink:0}.hamburger{display:none;flex-direction:column;gap:5px;padding:8px;margin-left:auto}.hamburger span{display:block;width:24px;height:2px;background:#fff;border-radius:2px;transition:all var(--mid)}.nav-mobile{display:none;flex-direction:column;background:var(--secondary);border-top:1px solid rgba(255,255,255,.1);max-height:calc(100vh - var(--header-h));overflow-y:auto}.mobile-group{border-bottom:1px solid rgba(255,255,255,.08)}.mobile-group-header{display:flex;align-items:center;padding:14px 24px;color:#ffffffd9;font-size:15px;font-weight:500;cursor:pointer}.mobile-children{background:#0003}.mobile-child{display:flex;align-items:center;gap:8px;padding:10px 36px;font-size:14px;color:#ffffffb3}.mobile-child:hover{color:#fff}@media (max-width: 1024px){.nav-desktop,.header-cta{display:none}.hamburger,.header.mobile-open .nav-mobile{display:flex}.header.mobile-open{height:auto}}.footer{background:var(--secondary);color:#fffc}.footer-top{padding:60px 0}.footer-top-inner{display:grid;grid-template-columns:280px repeat(4,1fr);gap:40px}.footer-logo{display:flex;align-items:center;gap:10px;margin-bottom:16px}.footer-logo img{height:36px}.footer-logo-text{font-size:20px;font-weight:700;color:#fff}.footer-logo-text strong{color:var(--accent)}.footer-tagline{font-size:13px;line-height:1.8;color:#fff9;margin-bottom:20px}.footer-contact-list{display:flex;flex-direction:column;gap:8px}.footer-contact-item{display:flex;gap:10px;font-size:13px}.contact-label{color:#fff6;min-width:60px}.footer-contact-item a{color:var(--accent)}.footer-contact-item a:hover{text-decoration:underline}.footer-menu-title{font-size:13px;font-weight:700;color:#fff;letter-spacing:.5px;text-transform:uppercase;margin-bottom:16px;padding-bottom:8px;border-bottom:1px solid rgba(255,255,255,.1)}.footer-menu-list{display:flex;flex-direction:column;gap:10px}.footer-menu-list a{font-size:13px;color:#fff9;transition:color var(--fast)}.footer-menu-list a:hover{color:var(--accent)}.footer-bottom{border-top:1px solid rgba(255,255,255,.08);padding:18px 0}.footer-bottom-inner{display:flex;align-items:center;gap:24px;font-size:12px;color:#fff6}.footer-legal{display:flex;gap:16px}.footer-legal a{color:#fff6}.footer-legal a:hover{color:#fffc}.footer-copyright{flex:1;text-align:center}.footer-powered{color:#ffffff4d}.footer-powered strong{color:var(--accent)}@media (max-width: 1024px){.footer-top-inner{grid-template-columns:1fr 1fr}.footer-brand{grid-column:1 / -1}}@media (max-width: 768px){.footer-top-inner{grid-template-columns:1fr 1fr}.footer-bottom-inner{flex-direction:column;text-align:center;gap:12px}.footer-copyright{order:-1}}:root{--primary: #0051A2;--primary-dark: #003A7A;--primary-light: #E8F0FA;--accent: #00A3E0;--accent-dark: #0080B0;--secondary: #1A1A2E;--gray-900: #111827;--gray-800: #1F2937;--gray-700: #374151;--gray-600: #4B5563;--gray-400: #9CA3AF;--gray-200: #E5E7EB;--gray-100: #F3F4F6;--gray-50: #F9FAFB;--white: #FFFFFF;--success: #10B981;--warning: #F59E0B;--danger: #EF4444;--font-sans: "Noto Sans KR", "Inter", -apple-system, sans-serif;--font-en: "Inter", sans-serif;--container: 1280px;--header-h: 72px;--radius-sm: 6px;--radius: 12px;--radius-lg: 20px;--ease: cubic-bezier(.4,0,.2,1);--fast: .15s;--mid: .3s;--slow: .5s;--shadow-sm: 0 1px 3px rgba(0,0,0,.1);--shadow: 0 4px 16px rgba(0,0,0,.12);--shadow-lg: 0 12px 40px rgba(0,0,0,.16)}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html{scroll-behavior:smooth;font-size:16px}body{font-family:var(--font-sans);color:var(--gray-800);background:var(--white);line-height:1.6;-webkit-font-smoothing:antialiased}img{max-width:100%;height:auto;display:block}a{color:inherit;text-decoration:none}ul,ol{list-style:none}button{cursor:pointer;border:none;background:none;font-family:inherit}.container{max-width:var(--container);margin:0 auto;padding:0 24px}.section{padding:80px 0}.section-sm{padding:48px 0}.section-lg{padding:120px 0}.section-header{text-align:center;margin-bottom:56px}.section-label{display:inline-block;font-size:13px;font-weight:700;letter-spacing:2px;text-transform:uppercase;color:var(--accent);margin-bottom:12px}.section-title{font-size:clamp(28px,4vw,44px);font-weight:900;color:var(--gray-900);line-height:1.2}.section-title em{color:var(--primary);font-style:normal}.section-desc{margin-top:16px;font-size:17px;color:var(--gray-600);max-width:600px;margin-left:auto;margin-right:auto}.btn{display:inline-flex;align-items:center;gap:8px;padding:12px 28px;border-radius:var(--radius);font-size:15px;font-weight:600;transition:all var(--mid) var(--ease);line-height:1}.btn-primary{background:var(--primary);color:var(--white)}.btn-primary:hover{background:var(--primary-dark);transform:translateY(-2px);box-shadow:0 8px 24px #0051a24d}.btn-outline{border:2px solid var(--primary);color:var(--primary)}.btn-outline:hover{background:var(--primary);color:var(--white)}.btn-white{background:var(--white);color:var(--primary);font-weight:700}.btn-white:hover{background:var(--gray-100);transform:translateY(-2px)}.btn-lg{padding:16px 36px;font-size:16px}.btn-sm{padding:8px 20px;font-size:13px}.card{background:var(--white);border-radius:var(--radius);box-shadow:var(--shadow-sm);border:1px solid var(--gray-200);transition:all var(--mid) var(--ease);overflow:hidden}.card:hover{box-shadow:var(--shadow-lg);transform:translateY(-4px);border-color:var(--primary-light)}.grid-2{display:grid;grid-template-columns:repeat(2,1fr);gap:24px}.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}.grid-4{display:grid;grid-template-columns:repeat(4,1fr);gap:24px}.badge{display:inline-block;padding:3px 10px;border-radius:20px;font-size:12px;font-weight:600}.badge-primary{background:var(--primary-light);color:var(--primary)}.badge-accent{background:#00a3e01f;color:var(--accent-dark)}.badge-new{background:var(--danger);color:var(--white)}.divider{width:48px;height:4px;background:var(--accent);border-radius:2px;margin:16px auto 0}.divider-left{margin-left:0}::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:var(--gray-100)}::-webkit-scrollbar-thumb{background:var(--gray-400);border-radius:3px}@keyframes fadeUp{0%{opacity:0;transform:translateY(30px)}to{opacity:1;transform:translateY(0)}}.fade-up{animation:fadeUp var(--slow) var(--ease) both}@media (max-width: 1024px){.grid-4{grid-template-columns:repeat(2,1fr)}}@media (max-width: 768px){.section{padding:60px 0}.grid-2,.grid-3,.grid-4{grid-template-columns:1fr}.container{padding:0 16px}} diff --git a/backend/src/main/resources/static/favicon.ico b/backend/src/main/resources/static/favicon.ico new file mode 100644 index 00000000..3252b9f8 Binary files /dev/null and b/backend/src/main/resources/static/favicon.ico differ diff --git a/backend/src/main/resources/static/index.html b/backend/src/main/resources/static/index.html new file mode 100644 index 00000000..74161120 --- /dev/null +++ b/backend/src/main/resources/static/index.html @@ -0,0 +1,22 @@ + + + + + + + + + + + (주)지오정보기술 + + + + + + + + +
+ + diff --git a/backend/src/main/resources/static/logo-white.png b/backend/src/main/resources/static/logo-white.png new file mode 100644 index 00000000..0ae65e05 Binary files /dev/null and b/backend/src/main/resources/static/logo-white.png differ diff --git a/backend/src/main/resources/static/logo.png b/backend/src/main/resources/static/logo.png new file mode 100644 index 00000000..4f88262a Binary files /dev/null and b/backend/src/main/resources/static/logo.png differ diff --git a/backend/src/main/resources/static/screenshots/01_dashboard.png b/backend/src/main/resources/static/screenshots/01_dashboard.png new file mode 100644 index 00000000..6728dfd8 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/01_dashboard.png differ diff --git a/backend/src/main/resources/static/screenshots/01_home.png b/backend/src/main/resources/static/screenshots/01_home.png new file mode 100644 index 00000000..9dd704fe Binary files /dev/null and b/backend/src/main/resources/static/screenshots/01_home.png differ diff --git a/backend/src/main/resources/static/screenshots/01_home_viewport.png b/backend/src/main/resources/static/screenshots/01_home_viewport.png new file mode 100644 index 00000000..64e7d888 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/01_home_viewport.png differ diff --git a/backend/src/main/resources/static/screenshots/02_guardia.png b/backend/src/main/resources/static/screenshots/02_guardia.png new file mode 100644 index 00000000..df6d4c74 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/02_guardia.png differ diff --git a/backend/src/main/resources/static/screenshots/02_guardia_viewport.png b/backend/src/main/resources/static/screenshots/02_guardia_viewport.png new file mode 100644 index 00000000..19b5addd Binary files /dev/null and b/backend/src/main/resources/static/screenshots/02_guardia_viewport.png differ diff --git a/backend/src/main/resources/static/screenshots/02_sr_list.png b/backend/src/main/resources/static/screenshots/02_sr_list.png new file mode 100644 index 00000000..6728dfd8 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/02_sr_list.png differ diff --git a/backend/src/main/resources/static/screenshots/03_company.png b/backend/src/main/resources/static/screenshots/03_company.png new file mode 100644 index 00000000..88e925d3 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/03_company.png differ diff --git a/backend/src/main/resources/static/screenshots/03_company_viewport.png b/backend/src/main/resources/static/screenshots/03_company_viewport.png new file mode 100644 index 00000000..e64b8177 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/03_company_viewport.png differ diff --git a/backend/src/main/resources/static/screenshots/03_si_project.png b/backend/src/main/resources/static/screenshots/03_si_project.png new file mode 100644 index 00000000..6481c7dc Binary files /dev/null and b/backend/src/main/resources/static/screenshots/03_si_project.png differ diff --git a/backend/src/main/resources/static/screenshots/04_contact.png b/backend/src/main/resources/static/screenshots/04_contact.png new file mode 100644 index 00000000..6bfc0ebf Binary files /dev/null and b/backend/src/main/resources/static/screenshots/04_contact.png differ diff --git a/backend/src/main/resources/static/screenshots/04_contact_viewport.png b/backend/src/main/resources/static/screenshots/04_contact_viewport.png new file mode 100644 index 00000000..f456b4e8 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/04_contact_viewport.png differ diff --git a/backend/src/main/resources/static/screenshots/04_incidents.png b/backend/src/main/resources/static/screenshots/04_incidents.png new file mode 100644 index 00000000..a50691cb Binary files /dev/null and b/backend/src/main/resources/static/screenshots/04_incidents.png differ diff --git a/backend/src/main/resources/static/screenshots/05_agents.png b/backend/src/main/resources/static/screenshots/05_agents.png new file mode 100644 index 00000000..847ccb8f Binary files /dev/null and b/backend/src/main/resources/static/screenshots/05_agents.png differ diff --git a/backend/src/main/resources/static/screenshots/05_news.png b/backend/src/main/resources/static/screenshots/05_news.png new file mode 100644 index 00000000..48dc2141 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/05_news.png differ diff --git a/backend/src/main/resources/static/screenshots/05_news_viewport.png b/backend/src/main/resources/static/screenshots/05_news_viewport.png new file mode 100644 index 00000000..f212eb23 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/05_news_viewport.png differ diff --git a/backend/src/main/resources/static/screenshots/06_license.png b/backend/src/main/resources/static/screenshots/06_license.png new file mode 100644 index 00000000..52f91192 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/06_license.png differ diff --git a/backend/src/main/resources/static/screenshots/06_mobile_home.png b/backend/src/main/resources/static/screenshots/06_mobile_home.png new file mode 100644 index 00000000..c3f3355d Binary files /dev/null and b/backend/src/main/resources/static/screenshots/06_mobile_home.png differ diff --git a/backend/src/main/resources/static/screenshots/all-pages-result.json b/backend/src/main/resources/static/screenshots/all-pages-result.json new file mode 100644 index 00000000..49a94b33 --- /dev/null +++ b/backend/src/main/resources/static/screenshots/all-pages-result.json @@ -0,0 +1,212 @@ +[ + { + "page": "홈", + "url": "/", + "http": 200, + "loadMs": 5849, + "title": "(주)지오정보기술", + "h1": "AI 기반 인프라자율 운영 플랫폼", + "errors": 0, + "ok": true + }, + { + "page": "GUARDiA ITSM", + "url": "/solution/guardia", + "http": 200, + "loadMs": 1292, + "title": "(주)지오정보기술", + "h1": "GUARDiA ITSM", + "errors": 0, + "ok": true + }, + { + "page": "솔루션-ERP", + "url": "/solution/erp", + "http": 200, + "loadMs": 1767, + "title": "(주)지오정보기술", + "h1": "ERP 솔루션", + "errors": 0, + "ok": true + }, + { + "page": "솔루션-CRM", + "url": "/solution/crm", + "http": 200, + "loadMs": 1139, + "title": "(주)지오정보기술", + "h1": "CRM 솔루션", + "errors": 0, + "ok": true + }, + { + "page": "솔루션-BI", + "url": "/solution/bi", + "http": 200, + "loadMs": 966, + "title": "(주)지오정보기술", + "h1": "BI 솔루션", + "errors": 0, + "ok": true + }, + { + "page": "회사-CEO인사말", + "url": "/company/greeting", + "http": 200, + "loadMs": 1098, + "title": "(주)지오정보기술", + "h1": "CEO 인사말", + "errors": 0, + "ok": true + }, + { + "page": "회사-연혁", + "url": "/company/history", + "http": 200, + "loadMs": 1548, + "title": "(주)지오정보기술", + "h1": "연혁", + "errors": 0, + "ok": true + }, + { + "page": "회사-조직도", + "url": "/company/organization", + "http": 200, + "loadMs": 892, + "title": "(주)지오정보기술", + "h1": "조직도", + "errors": 0, + "ok": true + }, + { + "page": "회사-CI소개", + "url": "/company/ci", + "http": 200, + "loadMs": 1007, + "title": "(주)지오정보기술", + "h1": "CI 소개", + "errors": 0, + "ok": true + }, + { + "page": "회사-오시는길", + "url": "/company/location", + "http": 200, + "loadMs": 1070, + "title": "(주)지오정보기술", + "h1": "오시는 길", + "errors": 0, + "ok": true + }, + { + "page": "사업-레퍼런스", + "url": "/business/reference", + "http": 200, + "loadMs": 1111, + "title": "(주)지오정보기술", + "h1": "구축 레퍼런스", + "errors": 0, + "ok": true + }, + { + "page": "사업-파트너", + "url": "/business/partner", + "http": 200, + "loadMs": 1090, + "title": "(주)지오정보기술", + "h1": "파트너", + "errors": 0, + "ok": true + }, + { + "page": "지원-공지사항", + "url": "/support/notice", + "http": 200, + "loadMs": 949, + "title": "(주)지오정보기술", + "h1": "공지사항", + "errors": 0, + "ok": true + }, + { + "page": "지원-FAQ", + "url": "/support/faq", + "http": 200, + "loadMs": 931, + "title": "(주)지오정보기술", + "h1": "자주 묻는 질문", + "errors": 0, + "ok": true + }, + { + "page": "지원-카탈로그", + "url": "/support/catalog", + "http": 200, + "loadMs": 963, + "title": "(주)지오정보기술", + "h1": "카탈로그", + "errors": 0, + "ok": true + }, + { + "page": "지원-문의하기", + "url": "/support/contact", + "http": 200, + "loadMs": 1007, + "title": "(주)지오정보기술", + "h1": "문의하기", + "errors": 0, + "ok": true + }, + { + "page": "채용-공고", + "url": "/recruit/jobs", + "http": 200, + "loadMs": 984, + "title": "(주)지오정보기술", + "h1": "채용공고", + "errors": 0, + "ok": true + }, + { + "page": "채용-복리후생", + "url": "/recruit/welfare", + "http": 200, + "loadMs": 1275, + "title": "(주)지오정보기술", + "h1": "복리후생", + "errors": 0, + "ok": true + }, + { + "page": "채용-지원하기", + "url": "/recruit/apply", + "http": 200, + "loadMs": 880, + "title": "(주)지오정보기술", + "h1": "지원하기", + "errors": 0, + "ok": true + }, + { + "page": "뉴스-뉴스룸", + "url": "/news/newsroom", + "http": 200, + "loadMs": 1144, + "title": "(주)지오정보기술", + "h1": "뉴스룸", + "errors": 0, + "ok": true + }, + { + "page": "뉴스-블로그", + "url": "/news/blog", + "http": 200, + "loadMs": 989, + "title": "(주)지오정보기술", + "h1": "기술 블로그", + "errors": 0, + "ok": true + } +] \ No newline at end of file diff --git a/backend/src/main/resources/static/screenshots/business_partner.png b/backend/src/main/resources/static/screenshots/business_partner.png new file mode 100644 index 00000000..3dce8a21 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/business_partner.png differ diff --git a/backend/src/main/resources/static/screenshots/business_ref.png b/backend/src/main/resources/static/screenshots/business_ref.png new file mode 100644 index 00000000..8b93a0f9 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/business_ref.png differ diff --git a/backend/src/main/resources/static/screenshots/company_ci.png b/backend/src/main/resources/static/screenshots/company_ci.png new file mode 100644 index 00000000..2eb6f3ca Binary files /dev/null and b/backend/src/main/resources/static/screenshots/company_ci.png differ diff --git a/backend/src/main/resources/static/screenshots/company_greeting.png b/backend/src/main/resources/static/screenshots/company_greeting.png new file mode 100644 index 00000000..9f932701 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/company_greeting.png differ diff --git a/backend/src/main/resources/static/screenshots/company_history.png b/backend/src/main/resources/static/screenshots/company_history.png new file mode 100644 index 00000000..bc970cb1 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/company_history.png differ diff --git a/backend/src/main/resources/static/screenshots/company_location.png b/backend/src/main/resources/static/screenshots/company_location.png new file mode 100644 index 00000000..5132a049 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/company_location.png differ diff --git a/backend/src/main/resources/static/screenshots/company_org.png b/backend/src/main/resources/static/screenshots/company_org.png new file mode 100644 index 00000000..c38e7b0e Binary files /dev/null and b/backend/src/main/resources/static/screenshots/company_org.png differ diff --git a/backend/src/main/resources/static/screenshots/guardia.png b/backend/src/main/resources/static/screenshots/guardia.png new file mode 100644 index 00000000..19b5addd Binary files /dev/null and b/backend/src/main/resources/static/screenshots/guardia.png differ diff --git a/backend/src/main/resources/static/screenshots/home.png b/backend/src/main/resources/static/screenshots/home.png new file mode 100644 index 00000000..5b4df9de Binary files /dev/null and b/backend/src/main/resources/static/screenshots/home.png differ diff --git a/backend/src/main/resources/static/screenshots/news_blog.png b/backend/src/main/resources/static/screenshots/news_blog.png new file mode 100644 index 00000000..94697ec8 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/news_blog.png differ diff --git a/backend/src/main/resources/static/screenshots/news_newsroom.png b/backend/src/main/resources/static/screenshots/news_newsroom.png new file mode 100644 index 00000000..d799d773 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/news_newsroom.png differ diff --git a/backend/src/main/resources/static/screenshots/recruit_apply.png b/backend/src/main/resources/static/screenshots/recruit_apply.png new file mode 100644 index 00000000..8e79f187 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/recruit_apply.png differ diff --git a/backend/src/main/resources/static/screenshots/recruit_jobs.png b/backend/src/main/resources/static/screenshots/recruit_jobs.png new file mode 100644 index 00000000..951e94f3 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/recruit_jobs.png differ diff --git a/backend/src/main/resources/static/screenshots/recruit_welfare.png b/backend/src/main/resources/static/screenshots/recruit_welfare.png new file mode 100644 index 00000000..53752fb2 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/recruit_welfare.png differ diff --git a/backend/src/main/resources/static/screenshots/solution_bi.png b/backend/src/main/resources/static/screenshots/solution_bi.png new file mode 100644 index 00000000..6999f9f1 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/solution_bi.png differ diff --git a/backend/src/main/resources/static/screenshots/solution_crm.png b/backend/src/main/resources/static/screenshots/solution_crm.png new file mode 100644 index 00000000..a45d34d9 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/solution_crm.png differ diff --git a/backend/src/main/resources/static/screenshots/solution_erp.png b/backend/src/main/resources/static/screenshots/solution_erp.png new file mode 100644 index 00000000..c6471957 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/solution_erp.png differ diff --git a/backend/src/main/resources/static/screenshots/support_catalog.png b/backend/src/main/resources/static/screenshots/support_catalog.png new file mode 100644 index 00000000..e9ee2998 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/support_catalog.png differ diff --git a/backend/src/main/resources/static/screenshots/support_contact.png b/backend/src/main/resources/static/screenshots/support_contact.png new file mode 100644 index 00000000..f456b4e8 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/support_contact.png differ diff --git a/backend/src/main/resources/static/screenshots/support_faq.png b/backend/src/main/resources/static/screenshots/support_faq.png new file mode 100644 index 00000000..62006a57 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/support_faq.png differ diff --git a/backend/src/main/resources/static/screenshots/support_notice.png b/backend/src/main/resources/static/screenshots/support_notice.png new file mode 100644 index 00000000..eba6bd03 Binary files /dev/null and b/backend/src/main/resources/static/screenshots/support_notice.png differ diff --git a/backend/src/main/resources/static/screenshots/test-result.json b/backend/src/main/resources/static/screenshots/test-result.json new file mode 100644 index 00000000..04877fa2 --- /dev/null +++ b/backend/src/main/resources/static/screenshots/test-result.json @@ -0,0 +1,67 @@ +[ + { + "page": "홈", + "url": "/", + "status": 200, + "loadMs": 9745, + "title": "(주)지오정보기술", + "links": 37, + "images": 2, + "h1": 1, + "errors": 0, + "errorMsgs": [], + "screenshot": "C:\\GUARDiA\\workspace\\zioinfo-web\\frontend\\public\\screenshots\\01_home.png" + }, + { + "page": "GUARDiA 소개", + "url": "/solution/guardia", + "status": 200, + "loadMs": 1130, + "title": "(주)지오정보기술", + "links": 27, + "images": 8, + "h1": 1, + "errors": 0, + "errorMsgs": [], + "screenshot": "C:\\GUARDiA\\workspace\\zioinfo-web\\frontend\\public\\screenshots\\02_guardia.png" + }, + { + "page": "회사소개", + "url": "/company/greeting", + "status": 200, + "loadMs": 971, + "title": "(주)지오정보기술", + "links": 23, + "images": 2, + "h1": 1, + "errors": 0, + "errorMsgs": [], + "screenshot": "C:\\GUARDiA\\workspace\\zioinfo-web\\frontend\\public\\screenshots\\03_company.png" + }, + { + "page": "문의하기", + "url": "/support/contact", + "status": 200, + "loadMs": 890, + "title": "(주)지오정보기술", + "links": 24, + "images": 2, + "h1": 1, + "errors": 0, + "errorMsgs": [], + "screenshot": "C:\\GUARDiA\\workspace\\zioinfo-web\\frontend\\public\\screenshots\\04_contact.png" + }, + { + "page": "뉴스", + "url": "/news/press", + "status": 200, + "loadMs": 1007, + "title": "(주)지오정보기술", + "links": 23, + "images": 2, + "h1": 1, + "errors": 0, + "errorMsgs": [], + "screenshot": "C:\\GUARDiA\\workspace\\zioinfo-web\\frontend\\public\\screenshots\\05_news.png" + } +] \ No newline at end of file diff --git a/deploy/01_oracle_cloud_guide.md b/deploy/01_oracle_cloud_guide.md new file mode 100644 index 00000000..825a4a84 --- /dev/null +++ b/deploy/01_oracle_cloud_guide.md @@ -0,0 +1,69 @@ +# Oracle Cloud Always Free — zio-server 구축 가이드 + +## 1단계: Oracle Cloud 계정 생성 + +1. https://www.oracle.com/cloud/free/ 접속 +2. "Start for free" 클릭 +3. 정보 입력: + - Country: South Korea + - 이름, 이메일, 비밀번호 +4. **신용카드 등록 필수** (과금 없음 — 인증용) +5. 가입 완료 후 홈 리전 선택: **South Korea Central (Seoul)** + +> ⚠️ 홈 리전은 변경 불가 — 반드시 Seoul 선택 + +--- + +## 2단계: VM 인스턴스 생성 (zio-server) + +### 콘솔 접속 +Oracle Cloud Console → Compute → Instances → Create Instance + +### 설정값 + +| 항목 | 값 | +|------|----| +| **Name** | `zio-server` | +| **Image** | Ubuntu 22.04 (Canonical) | +| **Shape** | VM.Standard.A1.Flex (Ampere) | +| **OCPU** | 4 | +| **Memory** | 24 GB | +| **Boot Volume** | 100 GB | +| **Network** | Default VCN, Public Subnet | +| **공인 IP** | Assign public IP: Yes | + +### SSH 키 생성 +``` +로컬에서: +ssh-keygen -t rsa -b 4096 -f C:\Users\{username}\.ssh\zio-server +``` +- 생성된 `zio-server.pub` 내용을 콘솔에 붙여넣기 + +### 생성 완료 +- 약 2~3분 후 Running 상태 확인 +- 공인 IP 메모 (예: 140.238.xxx.xxx) + +--- + +## 3단계: 방화벽 오픈 (Security List) + +Networking → Virtual Cloud Networks → Default VCN +→ Security Lists → Default Security List +→ Add Ingress Rules: + +| 포트 | 프로토콜 | 용도 | +|------|---------|------| +| 22 | TCP | SSH | +| 80 | TCP | HTTP | +| 443 | TCP | HTTPS | +| 8080 | TCP | Spring Boot (개발용) | + +--- + +## 4단계: SSH 접속 + +```powershell +ssh -i C:\Users\{username}\.ssh\zio-server ubuntu@{공인IP} +``` + +접속 성공 후 → 5단계 서버 설정 스크립트 실행 diff --git a/deploy/02_server_setup.sh b/deploy/02_server_setup.sh new file mode 100644 index 00000000..876b62ad --- /dev/null +++ b/deploy/02_server_setup.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# ============================================================ +# zio-server 초기 환경 구성 스크립트 +# Oracle Cloud Ubuntu 22.04 ARM (Ampere A1) +# 실행: bash 02_server_setup.sh +# ============================================================ + +set -e +GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' +info() { echo -e "${GREEN}[OK]${NC} $1"; } +section() { echo -e "\n${CYAN}=== $1 ===${NC}"; } + +section "1. 시스템 업데이트" +sudo apt-get update -y && sudo apt-get upgrade -y +sudo apt-get install -y curl wget git unzip net-tools ufw htop +info "시스템 업데이트 완료" + +section "2. Java 21 설치 (Spring Boot용)" +sudo apt-get install -y openjdk-21-jdk +java -version +info "Java 21 설치 완료" + +section "3. Node.js 20 LTS 설치 (React 빌드용)" +curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - +sudo apt-get install -y nodejs +node -v && npm -v +info "Node.js $(node -v) 설치 완료" + +section "4. Nginx 설치" +sudo apt-get install -y nginx +sudo systemctl enable nginx +sudo systemctl start nginx +info "Nginx 설치 완료" + +section "5. UFW 방화벽 설정" +sudo ufw allow ssh +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp +sudo ufw allow 8080/tcp +sudo ufw --force enable +sudo ufw status +info "방화벽 설정 완료" + +# Oracle Cloud 내부 iptables도 열기 (필수!) +section "6. Oracle Cloud iptables 규칙 추가" +sudo iptables -I INPUT 6 -m state --state NEW -p tcp --dport 80 -j ACCEPT +sudo iptables -I INPUT 6 -m state --state NEW -p tcp --dport 443 -j ACCEPT +sudo iptables -I INPUT 6 -m state --state NEW -p tcp --dport 8080 -j ACCEPT +sudo netfilter-persistent save 2>/dev/null || { + sudo apt-get install -y iptables-persistent + sudo netfilter-persistent save +} +info "iptables 규칙 저장 완료" + +section "7. 앱 디렉터리 생성" +sudo mkdir -p /var/www/zioinfo +sudo mkdir -p /opt/zioinfo/app +sudo chown -R ubuntu:ubuntu /var/www/zioinfo /opt/zioinfo +info "디렉터리 생성 완료" + +section "8. Nginx 설정" +sudo tee /etc/nginx/sites-available/zioinfo > /dev/null <<'NGINX' +server { + listen 80; + server_name _; + + root /var/www/zioinfo; + index index.html; + + # React SPA — 모든 경로를 index.html로 + location / { + try_files $uri $uri/ /index.html; + } + + # Spring Boot API 프록시 + location /api/ { + proxy_pass http://localhost:8080; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_read_timeout 60s; + } + + # 정적 파일 캐시 + location ~* \.(js|css|png|jpg|gif|ico|svg|woff2)$ { + expires 30d; + add_header Cache-Control "public, immutable"; + } + + # 보안 헤더 + add_header X-Frame-Options "SAMEORIGIN"; + add_header X-Content-Type-Options "nosniff"; + add_header X-XSS-Protection "1; mode=block"; + + # Gzip 압축 + gzip on; + gzip_types text/plain text/css application/javascript application/json image/svg+xml; + gzip_min_length 1024; +} +NGINX + +sudo ln -sf /etc/nginx/sites-available/zioinfo /etc/nginx/sites-enabled/ +sudo rm -f /etc/nginx/sites-enabled/default +sudo nginx -t && sudo systemctl reload nginx +info "Nginx 설정 완료" + +section "✅ 서버 초기 구성 완료!" +echo "" +echo -e "${YELLOW}다음 단계: 로컬에서 03_deploy.sh 실행${NC}" +echo -e "서버 IP: $(curl -s ifconfig.me)" diff --git a/deploy/03_deploy.ps1 b/deploy/03_deploy.ps1 new file mode 100644 index 00000000..a5f63745 --- /dev/null +++ b/deploy/03_deploy.ps1 @@ -0,0 +1,110 @@ +# ============================================================ +# zio-server 홈페이지 배포 스크립트 (Windows PowerShell) +# 실행: .\deploy\03_deploy.ps1 -ServerIP "140.238.xxx.xxx" +# ============================================================ + +param( + [Parameter(Mandatory=$true)] + [string]$ServerIP, + [string]$KeyPath = "$env:USERPROFILE\.ssh\zio-server", + [string]$User = "ubuntu" +) + +$GREEN = "`e[32m" +$YELLOW = "`e[33m" +$CYAN = "`e[36m" +$NC = "`e[0m" + +function Log-Info { param($msg) Write-Host "${GREEN}[OK]${NC} $msg" } +function Log-Section { param($msg) Write-Host "`n${CYAN}=== $msg ===${NC}" } +function Log-Warn { param($msg) Write-Host "${YELLOW}[!]${NC} $msg" } + +$SSH = "ssh -i `"$KeyPath`" -o StrictHostKeyChecking=no ${User}@${ServerIP}" +$SCP = "scp -i `"$KeyPath`" -o StrictHostKeyChecking=no" +$ROOT = "C:\GUARDiA\workspace\zioinfo-web" + +Log-Section "1. React 프론트엔드 빌드" +Set-Location "$ROOT\frontend" + +# vite.config.js 빌드 경로를 임시 dist로 변경 +$viteCfg = Get-Content "vite.config.js" -Raw +$buildCfg = $viteCfg -replace "outDir: '.*?'", "outDir: 'dist'" +$buildCfg | Set-Content "vite.config.js" -Encoding utf8 + +npm run build +if ($LASTEXITCODE -ne 0) { Write-Error "빌드 실패"; exit 1 } +Log-Info "React 빌드 완료 → frontend/dist/" + +Log-Section "2. 빌드 파일 서버 업로드" +Invoke-Expression "$SSH 'rm -rf /var/www/zioinfo/* && mkdir -p /var/www/zioinfo'" +Invoke-Expression "$SCP -r `"$ROOT\frontend\dist\*`" ${User}@${ServerIP}:/var/www/zioinfo/" +Log-Info "정적 파일 업로드 완료" + +Log-Section "3. Spring Boot JAR 빌드" +Set-Location "$ROOT" +if (Test-Path "pom.xml") { + # Maven 빌드 (Spring Boot 백엔드) + $mvnw = if (Test-Path "mvnw.cmd") { ".\mvnw.cmd" } else { "mvn" } + & $mvnw clean package -DskipTests -q + $jar = Get-ChildItem "target\*.jar" -Exclude "*sources*" | Select-Object -First 1 + if ($jar) { + Log-Info "JAR 빌드 완료: $($jar.Name)" + Invoke-Expression "$SCP `"$($jar.FullName)`" ${User}@${ServerIP}:/opt/zioinfo/app/zioinfo.jar" + Log-Info "JAR 업로드 완료" + } +} else { + Log-Warn "pom.xml 없음 — Spring Boot 배포 스킵 (정적 파일만 배포)" +} + +Log-Section "4. systemd 서비스 등록 (Spring Boot)" +$serviceScript = @' +# Spring Boot 서비스 설정 +sudo tee /etc/systemd/system/zioinfo.service > /dev/null </dev/null || echo "서비스 시작 대기 중..." +'@ + +if (Test-Path "$ROOT\target\*.jar") { + Invoke-Expression "$SSH '$serviceScript'" + Log-Info "Spring Boot 서비스 등록 완료" +} + +Log-Section "5. Nginx 재시작 및 최종 확인" +$checkScript = @" +sudo systemctl reload nginx +echo '--- Nginx 상태 ---' +sudo systemctl is-active nginx +echo '--- 포트 확인 ---' +ss -tlnp | grep -E ':80|:443|:8080' +echo '--- 디스크 사용량 ---' +df -h / +echo '--- 메모리 ---' +free -h +"@ +Invoke-Expression "$SSH '$checkScript'" + +Log-Section "✅ 배포 완료!" +Write-Host "" +Write-Host "${GREEN}홈페이지 주소:${NC} http://$ServerIP" +Write-Host "${GREEN}SSH 접속:${NC} ssh -i `"$KeyPath`" ubuntu@$ServerIP" +Write-Host "" +Write-Host "${YELLOW}브라우저에서 확인:${NC}" +Start-Process "http://$ServerIP" diff --git a/deploy/04_ssl_setup.sh b/deploy/04_ssl_setup.sh new file mode 100644 index 00000000..ffd3cea6 --- /dev/null +++ b/deploy/04_ssl_setup.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# ============================================================ +# SSL 인증서 설정 (Let's Encrypt / Certbot) +# 도메인이 있을 경우 실행 +# 실행: bash 04_ssl_setup.sh yourdomain.com +# ============================================================ + +DOMAIN=${1:-"zioinfo.co.kr"} + +echo "[1] Certbot 설치" +sudo apt-get install -y certbot python3-certbot-nginx + +echo "[2] SSL 인증서 발급 — $DOMAIN" +sudo certbot --nginx -d $DOMAIN -d www.$DOMAIN \ + --non-interactive --agree-tos --email admin@$DOMAIN \ + --redirect + +echo "[3] 자동 갱신 확인" +sudo certbot renew --dry-run + +echo "[4] Nginx 재시작" +sudo systemctl reload nginx + +echo "✅ SSL 설정 완료!" +echo " https://$DOMAIN 으로 접속하세요" diff --git a/deploy/05_update_deploy.sh b/deploy/05_update_deploy.sh new file mode 100644 index 00000000..8a0138f7 --- /dev/null +++ b/deploy/05_update_deploy.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# ============================================================ +# 빠른 업데이트 배포 스크립트 (서버에서 실행) +# 로컬에서 SCP로 파일 올린 후 서버에서 실행 +# 실행: bash 05_update_deploy.sh +# ============================================================ + +echo "[1] 새 파일 적용" +sudo cp -r /tmp/dist/* /var/www/zioinfo/ +sudo chown -R www-data:www-data /var/www/zioinfo/ + +echo "[2] Spring Boot 재시작 (있을 경우)" +if systemctl is-active --quiet zioinfo; then + sudo systemctl restart zioinfo + echo " Spring Boot 재시작됨" +fi + +echo "[3] Nginx 재로드" +sudo nginx -t && sudo systemctl reload nginx + +echo "✅ 업데이트 완료! $(date)" diff --git a/deploy/06_guardia_server_setup.sh b/deploy/06_guardia_server_setup.sh new file mode 100644 index 00000000..d7f920df --- /dev/null +++ b/deploy/06_guardia_server_setup.sh @@ -0,0 +1,135 @@ +#!/bin/bash +# ============================================================ +# GUARDiA ITSM 서버 환경 구성 +# Oracle Cloud Ubuntu 22.04 ARM (Ampere A1) +# 실행: bash 06_guardia_server_setup.sh +# ============================================================ + +set -e +GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' +info() { echo -e "${GREEN}[OK]${NC} $1"; } +warn() { echo -e "${YELLOW}[!]${NC} $1"; } +section() { echo -e "\n${CYAN}════════════════════════════════${NC}"; echo -e "${CYAN} $1${NC}"; echo -e "${CYAN}════════════════════════════════${NC}"; } + +# ── 1. Python 3.11 ────────────────────────────────────────── +section "1. Python 3.11 설치" +sudo apt-get install -y python3.11 python3.11-venv python3.11-dev python3-pip +sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 1 +python3 --version +info "Python 3.11 설치 완료" + +# ── 2. PostgreSQL 15 ───────────────────────────────────────── +section "2. PostgreSQL 15 설치" +sudo apt-get install -y postgresql postgresql-contrib +sudo systemctl enable postgresql +sudo systemctl start postgresql + +# DB / 사용자 생성 +sudo -u postgres psql < /opt/guardia/app/.env < /dev/null </dev/null || true +fi + +# DB 마이그레이션 +python3 db_init.py --force 2>/dev/null || python3 -c " +from database import engine, Base +from models import * +import asyncio +async def init(): + async with engine.begin() as conn: + await conn.run_sync(Base.metadata.create_all) +asyncio.run(init()) +print('DB 초기화 완료') +" 2>/dev/null || echo "DB 초기화 스킵 (이미 존재)" + +echo "[4] 서비스 재시작" +sudo systemctl restart guardia +sleep 3 +sudo systemctl is-active guardia && echo "GUARDiA 서비스 실행 중" || echo "서비스 시작 실패 — 로그 확인 필요" + +echo "[5] 정리" +rm -rf /tmp/guardia_src /tmp/guardia_deploy.zip +echo "배포 완료!" +'@ + +Invoke-Expression "$SSH 'bash -s'" | bash -s <<< "$deployScript" + +Log-Section "4. 접속 확인" +$checkScript = @" +echo '--- GUARDiA 서비스 상태 ---' +sudo systemctl status guardia --no-pager -l | head -20 +echo '' +echo '--- 포트 확인 ---' +ss -tlnp | grep -E ':8001|:8080|:80' +echo '' +echo '--- 메모리 사용량 ---' +free -h +echo '' +echo '--- GUARDiA API 헬스체크 ---' +sleep 2 +curl -s http://localhost:8001/api/admin/health | python3 -m json.tool 2>/dev/null || echo 'API 응답 대기 중...' +"@ +Invoke-Expression "$SSH '$checkScript'" + +Write-Host "" +Write-Host "`e[32m✅ GUARDiA ITSM 배포 완료!`e[0m" +Write-Host "" +Write-Host " 홈페이지: http://$ServerIP" +Write-Host " GUARDiA ITSM: http://$ServerIP`:8001" +Write-Host " 관리자 로그인: admin / admin (최초 접속 후 변경 필수)" +Write-Host "" +Write-Host "`e[33m보안 권고:`e[0m" +Write-Host " 1. 최초 로그인 후 즉시 비밀번호 변경" +Write-Host " 2. MFA 활성화: POST /api/auth/mfa/setup" +Write-Host " 3. 포트 8001 → Nginx 뒤로 숨기기 (07_nginx_all.sh 실행)" diff --git a/deploy/09_full_deploy_guide.md b/deploy/09_full_deploy_guide.md new file mode 100644 index 00000000..3cf53dc1 --- /dev/null +++ b/deploy/09_full_deploy_guide.md @@ -0,0 +1,44 @@ +# zio-server 전체 배포 가이드 + +## 서버 구성 완료 후 실행 순서 + +```bash +# 1. 기본 환경 (Java, Node, Nginx) +bash 02_server_setup.sh + +# 2. GUARDiA 환경 (Python, PostgreSQL, Ollama) +bash 06_guardia_server_setup.sh + +# 3. Nginx 통합 설정 +bash 07_nginx_all.sh zioinfo.co.kr itsm.zioinfo.co.kr + +# 4. 홈페이지 배포 (Windows에서) +.\deploy\03_deploy.ps1 -ServerIP "서버IP" + +# 5. GUARDiA 배포 (Windows에서) +.\deploy\08_deploy_guardia.ps1 -ServerIP "서버IP" + +# 6. SSL 인증서 (도메인 있을 때) +bash 04_ssl_setup.sh zioinfo.co.kr +``` + +## 최종 서비스 목록 + +| 서비스 | 주소 | 포트 | +|--------|------|------| +| 지오정보기술 홈페이지 | http://zioinfo.co.kr | 80/443 | +| GUARDiA ITSM | http://itsm.zioinfo.co.kr | 80/443 | +| PostgreSQL | 내부 전용 | 5432 | +| Ollama LLM | 내부 전용 | 11434 | + +## 리소스 사용 예상 + +| 구성 요소 | CPU | RAM | +|-----------|-----|-----| +| Nginx | 0.1 OCPU | 50 MB | +| Spring Boot | 0.5 OCPU | 512 MB | +| FastAPI (GUARDiA) | 0.5 OCPU | 300 MB | +| PostgreSQL | 0.3 OCPU | 256 MB | +| Ollama + LLaMA-3 8B | 1.0 OCPU | 6 GB | +| **합계** | **2.4 OCPU** | **~7.1 GB** | +| **여유** | **1.6 OCPU** | **~16.9 GB** ✅ | diff --git a/deploy/10_gitea_smtp_setup.sh b/deploy/10_gitea_smtp_setup.sh new file mode 100644 index 00000000..ef2d41f0 --- /dev/null +++ b/deploy/10_gitea_smtp_setup.sh @@ -0,0 +1,258 @@ +#!/bin/bash +# ============================================================ +# Gitea (Git 서버) + SMTP (Postfix) 설치 스크립트 +# Oracle Cloud Ubuntu 22.04 ARM (Ampere A1) +# 실행: bash 10_gitea_smtp_setup.sh [도메인] +# ============================================================ + +set -e +DOMAIN=${1:-"$(curl -s ifconfig.me)"} +GITEA_DOMAIN="git.${DOMAIN}" +GREEN='\033[0;32m'; CYAN='\033[0;36m'; YELLOW='\033[1;33m'; NC='\033[0m' +info() { echo -e "${GREEN}[OK]${NC} $1"; } +section() { echo -e "\n${CYAN}════════════════════════════════${NC}"; echo -e "${CYAN} $1${NC}"; echo -e "${CYAN}════════════════════════════════${NC}"; } + +# ──────────────────────────────────────────────── +# PART 1: Gitea 설치 +# ──────────────────────────────────────────────── + +section "1. Gitea 사용자 생성" +sudo adduser --system --shell /bin/bash --gecos 'Git Version Control' \ + --group --disabled-password --home /home/git git 2>/dev/null || true +info "git 사용자 준비 완료" + +section "2. Gitea 바이너리 다운로드 (ARM64)" +GITEA_VER="1.22.3" +sudo mkdir -p /opt/gitea/bin +sudo wget -q "https://dl.gitea.com/gitea/${GITEA_VER}/gitea-${GITEA_VER}-linux-arm64" \ + -O /opt/gitea/bin/gitea +sudo chmod +x /opt/gitea/bin/gitea +sudo ln -sf /opt/gitea/bin/gitea /usr/local/bin/gitea +gitea --version +info "Gitea ${GITEA_VER} 다운로드 완료" + +section "3. Gitea 디렉터리 구조" +sudo mkdir -p /var/lib/gitea/{custom,data,log} +sudo mkdir -p /etc/gitea +sudo chown -R git:git /var/lib/gitea /etc/gitea +sudo chmod -R 750 /var/lib/gitea /etc/gitea +info "Gitea 디렉터리 생성 완료" + +section "4. Gitea PostgreSQL DB 생성" +sudo -u postgres psql </dev/null || true +CREATE USER gitea WITH PASSWORD 'G1tea_2026!'; +CREATE DATABASE gitea_db OWNER gitea; +GRANT ALL PRIVILEGES ON DATABASE gitea_db TO gitea; +PSQL +info "Gitea DB 생성 완료" + +section "5. Gitea 설정 파일 생성" +sudo tee /etc/gitea/app.ini > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < + + + + + + + + + + (주)지오정보기술 + + + + + + +
+ + + diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 00000000..6641d059 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,2174 @@ +{ + "name": "zioinfo-web-frontend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "zioinfo-web-frontend", + "version": "1.0.0", + "dependencies": { + "axios": "^1.7.2", + "react": "^18.3.1", + "react-countup": "^6.5.3", + "react-dom": "^18.3.1", + "react-intersection-observer": "^9.10.3", + "react-router-dom": "^6.23.1", + "react-scroll": "^1.9.0", + "swiper": "^11.1.4" + }, + "devDependencies": { + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.0", + "vite": "^5.2.11" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@remix-run/router": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.3.tgz", + "integrity": "sha512-4An71tdz9X8+3sI4Qqqd2LWd9vS39J7sqd9EU4Scw7TJE/qB10Flv/UuqbPVgfQV9XoK8Np6jNquZitnZq5i+Q==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz", + "integrity": "sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.4.tgz", + "integrity": "sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.4.tgz", + "integrity": "sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.4.tgz", + "integrity": "sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.4.tgz", + "integrity": "sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.4.tgz", + "integrity": "sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.4.tgz", + "integrity": "sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.4.tgz", + "integrity": "sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.4.tgz", + "integrity": "sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.4.tgz", + "integrity": "sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.4.tgz", + "integrity": "sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.4.tgz", + "integrity": "sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.4.tgz", + "integrity": "sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.4.tgz", + "integrity": "sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.4.tgz", + "integrity": "sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.4.tgz", + "integrity": "sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.4.tgz", + "integrity": "sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.4.tgz", + "integrity": "sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.4.tgz", + "integrity": "sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.4.tgz", + "integrity": "sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.4.tgz", + "integrity": "sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.4.tgz", + "integrity": "sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.4.tgz", + "integrity": "sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.4.tgz", + "integrity": "sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.4.tgz", + "integrity": "sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.29", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.29.tgz", + "integrity": "sha512-ch0qJdr2JY0r04NXSprbK6TXOgnaJ1Tz23fm5W+z0/CBah6BSBc3n96h7K9GOtwh0HrilNWHIBzE1Ko4Dcw/Wg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz", + "integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.32", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.32.tgz", + "integrity": "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/countup.js": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.10.0.tgz", + "integrity": "sha512-QQpZx7oYxsR+OeITlZe46fY/OQjV11oBqjY8wgIXzLU2jIz8GzOrbMhqKLysGY8bWI3T1ZNrYkwGzKb4JNgyzg==", + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.364", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.364.tgz", + "integrity": "sha512-G/dYE3+AYhyHwzTwg8UbnXf7zqMERYh7l2jJ3QujhFsH8agSYwtnGAR2aZ7f0AakIKJXd5En/Hre4igIUrdlYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz", + "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-countup": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/react-countup/-/react-countup-6.5.3.tgz", + "integrity": "sha512-udnqVQitxC7QWADSPDOxVWULkLvKUWrDapn5i53HE4DPRVgs+Y5rr4bo25qEl8jSh+0l2cToJgGMx+clxPM3+w==", + "license": "MIT", + "dependencies": { + "countup.js": "^2.8.0" + }, + "peerDependencies": { + "react": ">= 16.3.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-intersection-observer": { + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.16.0.tgz", + "integrity": "sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA==", + "license": "MIT", + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.30.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.4.tgz", + "integrity": "sha512-SVUsDe+DybHM/WmYKIVYhZh1o5Dcuf16yM6WjG02Q9XVFMZIJyHYhwrr6bFBXZkVP6z69kNkMyBCujt8FaFLJA==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.4.tgz", + "integrity": "sha512-q4HvNl+mmDdkS0g+MqiBZNteQJCuimWoOyHMy4T/RQLAn9Z29+E91QXRaxOujeMl2HTzRSS0KFPd7lxX3PjV0Q==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.3", + "react-router": "6.30.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-scroll": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/react-scroll/-/react-scroll-1.9.3.tgz", + "integrity": "sha512-xv7FXqF3k63aSLNu4/NjFvRNI0ge7DmmmsbeGarP7LZVAlJMSjUuW3dTtLxp1Afijyv0lS2qwC0GiFHvx1KBHQ==", + "license": "MIT", + "dependencies": { + "lodash.throttle": "^4.1.1", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": "^15.5.4 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^15.5.4 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/rollup": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.4.tgz", + "integrity": "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.4", + "@rollup/rollup-android-arm64": "4.60.4", + "@rollup/rollup-darwin-arm64": "4.60.4", + "@rollup/rollup-darwin-x64": "4.60.4", + "@rollup/rollup-freebsd-arm64": "4.60.4", + "@rollup/rollup-freebsd-x64": "4.60.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.4", + "@rollup/rollup-linux-arm-musleabihf": "4.60.4", + "@rollup/rollup-linux-arm64-gnu": "4.60.4", + "@rollup/rollup-linux-arm64-musl": "4.60.4", + "@rollup/rollup-linux-loong64-gnu": "4.60.4", + "@rollup/rollup-linux-loong64-musl": "4.60.4", + "@rollup/rollup-linux-ppc64-gnu": "4.60.4", + "@rollup/rollup-linux-ppc64-musl": "4.60.4", + "@rollup/rollup-linux-riscv64-gnu": "4.60.4", + "@rollup/rollup-linux-riscv64-musl": "4.60.4", + "@rollup/rollup-linux-s390x-gnu": "4.60.4", + "@rollup/rollup-linux-x64-gnu": "4.60.4", + "@rollup/rollup-linux-x64-musl": "4.60.4", + "@rollup/rollup-openbsd-x64": "4.60.4", + "@rollup/rollup-openharmony-arm64": "4.60.4", + "@rollup/rollup-win32-arm64-msvc": "4.60.4", + "@rollup/rollup-win32-ia32-msvc": "4.60.4", + "@rollup/rollup-win32-x64-gnu": "4.60.4", + "@rollup/rollup-win32-x64-msvc": "4.60.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/swiper": { + "version": "11.2.10", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.2.10.tgz", + "integrity": "sha512-RMeVUUjTQH+6N3ckimK93oxz6Sn5la4aDlgPzB+rBrG/smPdCTicXyhxa+woIpopz+jewEloiEE3lKo1h9w2YQ==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/swiperjs" + }, + { + "type": "open_collective", + "url": "http://opencollective.com/swiper" + } + ], + "license": "MIT", + "engines": { + "node": ">= 4.7.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 00000000..07a25ea7 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,26 @@ +{ + "name": "zioinfo-web-frontend", + "version": "1.0.0", + "private": true, + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.23.1", + "axios": "^1.7.2", + "swiper": "^11.1.4", + "react-intersection-observer": "^9.10.3", + "react-countup": "^6.5.3", + "react-scroll": "^1.9.0" + }, + "devDependencies": { + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.0", + "vite": "^5.2.11" + } +} diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico new file mode 100644 index 00000000..3252b9f8 Binary files /dev/null and b/frontend/public/favicon.ico differ diff --git a/frontend/public/index.html b/frontend/public/index.html new file mode 100644 index 00000000..fe630a0e --- /dev/null +++ b/frontend/public/index.html @@ -0,0 +1,18 @@ + + + + + + + + (주)지오정보기술 + + + + + + +
+ + + diff --git a/frontend/public/logo-white.png b/frontend/public/logo-white.png new file mode 100644 index 00000000..0ae65e05 Binary files /dev/null and b/frontend/public/logo-white.png differ diff --git a/frontend/public/logo.png b/frontend/public/logo.png new file mode 100644 index 00000000..4f88262a Binary files /dev/null and b/frontend/public/logo.png differ diff --git a/frontend/public/screenshots/01_dashboard.png b/frontend/public/screenshots/01_dashboard.png new file mode 100644 index 00000000..6728dfd8 Binary files /dev/null and b/frontend/public/screenshots/01_dashboard.png differ diff --git a/frontend/public/screenshots/01_home.png b/frontend/public/screenshots/01_home.png new file mode 100644 index 00000000..9dd704fe Binary files /dev/null and b/frontend/public/screenshots/01_home.png differ diff --git a/frontend/public/screenshots/01_home_viewport.png b/frontend/public/screenshots/01_home_viewport.png new file mode 100644 index 00000000..64e7d888 Binary files /dev/null and b/frontend/public/screenshots/01_home_viewport.png differ diff --git a/frontend/public/screenshots/02_guardia.png b/frontend/public/screenshots/02_guardia.png new file mode 100644 index 00000000..df6d4c74 Binary files /dev/null and b/frontend/public/screenshots/02_guardia.png differ diff --git a/frontend/public/screenshots/02_guardia_viewport.png b/frontend/public/screenshots/02_guardia_viewport.png new file mode 100644 index 00000000..19b5addd Binary files /dev/null and b/frontend/public/screenshots/02_guardia_viewport.png differ diff --git a/frontend/public/screenshots/02_sr_list.png b/frontend/public/screenshots/02_sr_list.png new file mode 100644 index 00000000..6728dfd8 Binary files /dev/null and b/frontend/public/screenshots/02_sr_list.png differ diff --git a/frontend/public/screenshots/03_company.png b/frontend/public/screenshots/03_company.png new file mode 100644 index 00000000..88e925d3 Binary files /dev/null and b/frontend/public/screenshots/03_company.png differ diff --git a/frontend/public/screenshots/03_company_viewport.png b/frontend/public/screenshots/03_company_viewport.png new file mode 100644 index 00000000..e64b8177 Binary files /dev/null and b/frontend/public/screenshots/03_company_viewport.png differ diff --git a/frontend/public/screenshots/03_si_project.png b/frontend/public/screenshots/03_si_project.png new file mode 100644 index 00000000..6481c7dc Binary files /dev/null and b/frontend/public/screenshots/03_si_project.png differ diff --git a/frontend/public/screenshots/04_contact.png b/frontend/public/screenshots/04_contact.png new file mode 100644 index 00000000..6bfc0ebf Binary files /dev/null and b/frontend/public/screenshots/04_contact.png differ diff --git a/frontend/public/screenshots/04_contact_viewport.png b/frontend/public/screenshots/04_contact_viewport.png new file mode 100644 index 00000000..f456b4e8 Binary files /dev/null and b/frontend/public/screenshots/04_contact_viewport.png differ diff --git a/frontend/public/screenshots/04_incidents.png b/frontend/public/screenshots/04_incidents.png new file mode 100644 index 00000000..a50691cb Binary files /dev/null and b/frontend/public/screenshots/04_incidents.png differ diff --git a/frontend/public/screenshots/05_agents.png b/frontend/public/screenshots/05_agents.png new file mode 100644 index 00000000..847ccb8f Binary files /dev/null and b/frontend/public/screenshots/05_agents.png differ diff --git a/frontend/public/screenshots/05_news.png b/frontend/public/screenshots/05_news.png new file mode 100644 index 00000000..48dc2141 Binary files /dev/null and b/frontend/public/screenshots/05_news.png differ diff --git a/frontend/public/screenshots/05_news_viewport.png b/frontend/public/screenshots/05_news_viewport.png new file mode 100644 index 00000000..f212eb23 Binary files /dev/null and b/frontend/public/screenshots/05_news_viewport.png differ diff --git a/frontend/public/screenshots/06_license.png b/frontend/public/screenshots/06_license.png new file mode 100644 index 00000000..52f91192 Binary files /dev/null and b/frontend/public/screenshots/06_license.png differ diff --git a/frontend/public/screenshots/06_mobile_home.png b/frontend/public/screenshots/06_mobile_home.png new file mode 100644 index 00000000..c3f3355d Binary files /dev/null and b/frontend/public/screenshots/06_mobile_home.png differ diff --git a/frontend/public/screenshots/all-pages-result.json b/frontend/public/screenshots/all-pages-result.json new file mode 100644 index 00000000..49a94b33 --- /dev/null +++ b/frontend/public/screenshots/all-pages-result.json @@ -0,0 +1,212 @@ +[ + { + "page": "홈", + "url": "/", + "http": 200, + "loadMs": 5849, + "title": "(주)지오정보기술", + "h1": "AI 기반 인프라자율 운영 플랫폼", + "errors": 0, + "ok": true + }, + { + "page": "GUARDiA ITSM", + "url": "/solution/guardia", + "http": 200, + "loadMs": 1292, + "title": "(주)지오정보기술", + "h1": "GUARDiA ITSM", + "errors": 0, + "ok": true + }, + { + "page": "솔루션-ERP", + "url": "/solution/erp", + "http": 200, + "loadMs": 1767, + "title": "(주)지오정보기술", + "h1": "ERP 솔루션", + "errors": 0, + "ok": true + }, + { + "page": "솔루션-CRM", + "url": "/solution/crm", + "http": 200, + "loadMs": 1139, + "title": "(주)지오정보기술", + "h1": "CRM 솔루션", + "errors": 0, + "ok": true + }, + { + "page": "솔루션-BI", + "url": "/solution/bi", + "http": 200, + "loadMs": 966, + "title": "(주)지오정보기술", + "h1": "BI 솔루션", + "errors": 0, + "ok": true + }, + { + "page": "회사-CEO인사말", + "url": "/company/greeting", + "http": 200, + "loadMs": 1098, + "title": "(주)지오정보기술", + "h1": "CEO 인사말", + "errors": 0, + "ok": true + }, + { + "page": "회사-연혁", + "url": "/company/history", + "http": 200, + "loadMs": 1548, + "title": "(주)지오정보기술", + "h1": "연혁", + "errors": 0, + "ok": true + }, + { + "page": "회사-조직도", + "url": "/company/organization", + "http": 200, + "loadMs": 892, + "title": "(주)지오정보기술", + "h1": "조직도", + "errors": 0, + "ok": true + }, + { + "page": "회사-CI소개", + "url": "/company/ci", + "http": 200, + "loadMs": 1007, + "title": "(주)지오정보기술", + "h1": "CI 소개", + "errors": 0, + "ok": true + }, + { + "page": "회사-오시는길", + "url": "/company/location", + "http": 200, + "loadMs": 1070, + "title": "(주)지오정보기술", + "h1": "오시는 길", + "errors": 0, + "ok": true + }, + { + "page": "사업-레퍼런스", + "url": "/business/reference", + "http": 200, + "loadMs": 1111, + "title": "(주)지오정보기술", + "h1": "구축 레퍼런스", + "errors": 0, + "ok": true + }, + { + "page": "사업-파트너", + "url": "/business/partner", + "http": 200, + "loadMs": 1090, + "title": "(주)지오정보기술", + "h1": "파트너", + "errors": 0, + "ok": true + }, + { + "page": "지원-공지사항", + "url": "/support/notice", + "http": 200, + "loadMs": 949, + "title": "(주)지오정보기술", + "h1": "공지사항", + "errors": 0, + "ok": true + }, + { + "page": "지원-FAQ", + "url": "/support/faq", + "http": 200, + "loadMs": 931, + "title": "(주)지오정보기술", + "h1": "자주 묻는 질문", + "errors": 0, + "ok": true + }, + { + "page": "지원-카탈로그", + "url": "/support/catalog", + "http": 200, + "loadMs": 963, + "title": "(주)지오정보기술", + "h1": "카탈로그", + "errors": 0, + "ok": true + }, + { + "page": "지원-문의하기", + "url": "/support/contact", + "http": 200, + "loadMs": 1007, + "title": "(주)지오정보기술", + "h1": "문의하기", + "errors": 0, + "ok": true + }, + { + "page": "채용-공고", + "url": "/recruit/jobs", + "http": 200, + "loadMs": 984, + "title": "(주)지오정보기술", + "h1": "채용공고", + "errors": 0, + "ok": true + }, + { + "page": "채용-복리후생", + "url": "/recruit/welfare", + "http": 200, + "loadMs": 1275, + "title": "(주)지오정보기술", + "h1": "복리후생", + "errors": 0, + "ok": true + }, + { + "page": "채용-지원하기", + "url": "/recruit/apply", + "http": 200, + "loadMs": 880, + "title": "(주)지오정보기술", + "h1": "지원하기", + "errors": 0, + "ok": true + }, + { + "page": "뉴스-뉴스룸", + "url": "/news/newsroom", + "http": 200, + "loadMs": 1144, + "title": "(주)지오정보기술", + "h1": "뉴스룸", + "errors": 0, + "ok": true + }, + { + "page": "뉴스-블로그", + "url": "/news/blog", + "http": 200, + "loadMs": 989, + "title": "(주)지오정보기술", + "h1": "기술 블로그", + "errors": 0, + "ok": true + } +] \ No newline at end of file diff --git a/frontend/public/screenshots/business_partner.png b/frontend/public/screenshots/business_partner.png new file mode 100644 index 00000000..3dce8a21 Binary files /dev/null and b/frontend/public/screenshots/business_partner.png differ diff --git a/frontend/public/screenshots/business_ref.png b/frontend/public/screenshots/business_ref.png new file mode 100644 index 00000000..8b93a0f9 Binary files /dev/null and b/frontend/public/screenshots/business_ref.png differ diff --git a/frontend/public/screenshots/company_ci.png b/frontend/public/screenshots/company_ci.png new file mode 100644 index 00000000..2eb6f3ca Binary files /dev/null and b/frontend/public/screenshots/company_ci.png differ diff --git a/frontend/public/screenshots/company_greeting.png b/frontend/public/screenshots/company_greeting.png new file mode 100644 index 00000000..9f932701 Binary files /dev/null and b/frontend/public/screenshots/company_greeting.png differ diff --git a/frontend/public/screenshots/company_history.png b/frontend/public/screenshots/company_history.png new file mode 100644 index 00000000..bc970cb1 Binary files /dev/null and b/frontend/public/screenshots/company_history.png differ diff --git a/frontend/public/screenshots/company_location.png b/frontend/public/screenshots/company_location.png new file mode 100644 index 00000000..5132a049 Binary files /dev/null and b/frontend/public/screenshots/company_location.png differ diff --git a/frontend/public/screenshots/company_org.png b/frontend/public/screenshots/company_org.png new file mode 100644 index 00000000..c38e7b0e Binary files /dev/null and b/frontend/public/screenshots/company_org.png differ diff --git a/frontend/public/screenshots/guardia.png b/frontend/public/screenshots/guardia.png new file mode 100644 index 00000000..19b5addd Binary files /dev/null and b/frontend/public/screenshots/guardia.png differ diff --git a/frontend/public/screenshots/home.png b/frontend/public/screenshots/home.png new file mode 100644 index 00000000..5b4df9de Binary files /dev/null and b/frontend/public/screenshots/home.png differ diff --git a/frontend/public/screenshots/news_blog.png b/frontend/public/screenshots/news_blog.png new file mode 100644 index 00000000..94697ec8 Binary files /dev/null and b/frontend/public/screenshots/news_blog.png differ diff --git a/frontend/public/screenshots/news_newsroom.png b/frontend/public/screenshots/news_newsroom.png new file mode 100644 index 00000000..d799d773 Binary files /dev/null and b/frontend/public/screenshots/news_newsroom.png differ diff --git a/frontend/public/screenshots/recruit_apply.png b/frontend/public/screenshots/recruit_apply.png new file mode 100644 index 00000000..8e79f187 Binary files /dev/null and b/frontend/public/screenshots/recruit_apply.png differ diff --git a/frontend/public/screenshots/recruit_jobs.png b/frontend/public/screenshots/recruit_jobs.png new file mode 100644 index 00000000..951e94f3 Binary files /dev/null and b/frontend/public/screenshots/recruit_jobs.png differ diff --git a/frontend/public/screenshots/recruit_welfare.png b/frontend/public/screenshots/recruit_welfare.png new file mode 100644 index 00000000..53752fb2 Binary files /dev/null and b/frontend/public/screenshots/recruit_welfare.png differ diff --git a/frontend/public/screenshots/solution_bi.png b/frontend/public/screenshots/solution_bi.png new file mode 100644 index 00000000..6999f9f1 Binary files /dev/null and b/frontend/public/screenshots/solution_bi.png differ diff --git a/frontend/public/screenshots/solution_crm.png b/frontend/public/screenshots/solution_crm.png new file mode 100644 index 00000000..a45d34d9 Binary files /dev/null and b/frontend/public/screenshots/solution_crm.png differ diff --git a/frontend/public/screenshots/solution_erp.png b/frontend/public/screenshots/solution_erp.png new file mode 100644 index 00000000..c6471957 Binary files /dev/null and b/frontend/public/screenshots/solution_erp.png differ diff --git a/frontend/public/screenshots/support_catalog.png b/frontend/public/screenshots/support_catalog.png new file mode 100644 index 00000000..e9ee2998 Binary files /dev/null and b/frontend/public/screenshots/support_catalog.png differ diff --git a/frontend/public/screenshots/support_contact.png b/frontend/public/screenshots/support_contact.png new file mode 100644 index 00000000..f456b4e8 Binary files /dev/null and b/frontend/public/screenshots/support_contact.png differ diff --git a/frontend/public/screenshots/support_faq.png b/frontend/public/screenshots/support_faq.png new file mode 100644 index 00000000..62006a57 Binary files /dev/null and b/frontend/public/screenshots/support_faq.png differ diff --git a/frontend/public/screenshots/support_notice.png b/frontend/public/screenshots/support_notice.png new file mode 100644 index 00000000..eba6bd03 Binary files /dev/null and b/frontend/public/screenshots/support_notice.png differ diff --git a/frontend/public/screenshots/test-result.json b/frontend/public/screenshots/test-result.json new file mode 100644 index 00000000..04877fa2 --- /dev/null +++ b/frontend/public/screenshots/test-result.json @@ -0,0 +1,67 @@ +[ + { + "page": "홈", + "url": "/", + "status": 200, + "loadMs": 9745, + "title": "(주)지오정보기술", + "links": 37, + "images": 2, + "h1": 1, + "errors": 0, + "errorMsgs": [], + "screenshot": "C:\\GUARDiA\\workspace\\zioinfo-web\\frontend\\public\\screenshots\\01_home.png" + }, + { + "page": "GUARDiA 소개", + "url": "/solution/guardia", + "status": 200, + "loadMs": 1130, + "title": "(주)지오정보기술", + "links": 27, + "images": 8, + "h1": 1, + "errors": 0, + "errorMsgs": [], + "screenshot": "C:\\GUARDiA\\workspace\\zioinfo-web\\frontend\\public\\screenshots\\02_guardia.png" + }, + { + "page": "회사소개", + "url": "/company/greeting", + "status": 200, + "loadMs": 971, + "title": "(주)지오정보기술", + "links": 23, + "images": 2, + "h1": 1, + "errors": 0, + "errorMsgs": [], + "screenshot": "C:\\GUARDiA\\workspace\\zioinfo-web\\frontend\\public\\screenshots\\03_company.png" + }, + { + "page": "문의하기", + "url": "/support/contact", + "status": 200, + "loadMs": 890, + "title": "(주)지오정보기술", + "links": 24, + "images": 2, + "h1": 1, + "errors": 0, + "errorMsgs": [], + "screenshot": "C:\\GUARDiA\\workspace\\zioinfo-web\\frontend\\public\\screenshots\\04_contact.png" + }, + { + "page": "뉴스", + "url": "/news/press", + "status": 200, + "loadMs": 1007, + "title": "(주)지오정보기술", + "links": 23, + "images": 2, + "h1": 1, + "errors": 0, + "errorMsgs": [], + "screenshot": "C:\\GUARDiA\\workspace\\zioinfo-web\\frontend\\public\\screenshots\\05_news.png" + } +] \ No newline at end of file diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx new file mode 100644 index 00000000..04abb3de --- /dev/null +++ b/frontend/src/App.jsx @@ -0,0 +1,84 @@ +import React, { Suspense, lazy } from 'react'; +import { Routes, Route, Navigate, useLocation } from 'react-router-dom'; +import Header from './components/layout/Header'; +import Footer from './components/layout/Footer'; + +const Home = lazy(() => import('./pages/Home')); +const GuardiaDetail = lazy(() => import('./pages/GuardiaDetail')); +const SolutionPage = lazy(() => import('./pages/SolutionPage')); +const Company = lazy(() => import('./pages/Company')); +const Business = lazy(() => import('./pages/Business')); +const Contact = lazy(() => import('./pages/Contact')); +const Support = lazy(() => import('./pages/Support')); +const NewsPage = lazy(() => import('./pages/NewsPage')); +const Recruit = lazy(() => import('./pages/Recruit')); +const NotFound = lazy(() => import('./pages/NotFound')); + +// Admin +const AdminLogin = lazy(() => import('./pages/admin/AdminLogin')); +const AdminLayout = lazy(() => import('./pages/admin/AdminLayout')); +const AdminDashboard = lazy(() => import('./pages/admin/AdminDashboard')); +const AdminNews = lazy(() => import('./pages/admin/AdminNews')); +const AdminInquiry = lazy(() => import('./pages/admin/AdminInquiry')); +const AdminRecruit = lazy(() => import('./pages/admin/AdminRecruit')); +const AdminSettings = lazy(() => import('./pages/admin/AdminSettings')); + +function Loading() { + return ( +
+ 로딩 중... +
+ ); +} + +function PublicLayout({ children }) { + return ( + <> +
+ }>{children} +