Эх сурвалжийг харах

feat: Add 3D scanning prototype page

unknown 2 сар өмнө
parent
commit
a82bbe8ae3

+ 16 - 8
src/components/Header.vue

@@ -161,24 +161,32 @@ import LanguageSwitcher from "./LanguageSwitcher.vue";
 import Button from "./ui/button.vue";
 import { useAuthStore } from "@/stores/auth";
 import { currentLanguage } from "@/i18n";
+import { useFeatureFlags } from "@/composables/useFeatureFlags";
 
 const { t } = useI18n();
 const router = useRouter();
 const authStore = useAuthStore();
+const flags = useFeatureFlags();
 const mobileOpen = ref(false);
 const activeLang = computed(() => currentLanguage() || localStorage.getItem('locale') || 'en');
 
 const isLoggedIn = computed(() => !!authStore.user);
 const isAdmin = computed(() => authStore.user?.role === "admin");
 
-const navLinks = computed(() => [
-  { label: t("nav.services"), href: `/${activeLang.value}/#services`, isInternal: true },
-  { label: t("nav.materials"), href: `/${activeLang.value}/#materials`, isInternal: true },
-  { label: t("nav.nuances"), href: `/${activeLang.value}/nuances`, isInternal: true },
-  { label: t("nav.howItWorks"), href: `/${activeLang.value}/#process`, isInternal: true },
-  { label: t("nav.portfolio"), href: `/${activeLang.value}/portfolio`, isInternal: true },
-  { label: t("nav.philosophy"), href: `/${activeLang.value}/#philosophy`, isInternal: true },
-]);
+const navLinks = computed(() => {
+  const links = [
+    { label: t("nav.services"), href: `/${activeLang.value}/#services`, isInternal: true },
+    { label: t("nav.materials"), href: `/${activeLang.value}/#materials`, isInternal: true },
+    { label: t("nav.nuances"), href: `/${activeLang.value}/nuances`, isInternal: true },
+    { label: t("nav.howItWorks"), href: `/${activeLang.value}/#process`, isInternal: true },
+    { label: t("nav.portfolio"), href: `/${activeLang.value}/portfolio`, isInternal: true },
+    { label: t("nav.philosophy"), href: `/${activeLang.value}/#philosophy`, isInternal: true },
+  ];
+  if (flags.is3DScanningEnabled) {
+    links.splice(1, 0, { label: "3D Сканирование", href: `/${activeLang.value}/scanning`, isInternal: true });
+  }
+  return links;
+});
 
 async function handleLogout() {
   const currentPath = router.currentRoute.value.path;

+ 84 - 0
src/pages/Scanning.vue

@@ -0,0 +1,84 @@
+<template>
+  <div class="min-h-screen bg-background text-foreground flex flex-col">
+    <Header />
+    <main class="flex-1 max-w-5xl mx-auto w-full px-6 py-24 sm:py-32 space-y-16">
+      
+      <!-- Hero -->
+      <section class="text-center space-y-6">
+         <h1 class="text-4xl sm:text-6xl font-black tracking-tight">Услуга <span class="bg-gradient-to-r from-primary to-primary/60 bg-clip-text text-transparent">3D Сканирования</span></h1>
+         <p class="text-lg text-muted-foreground max-w-2xl mx-auto">
+           Оцифровка физических объектов с высокой точностью с помощью сканера metrology-класса Creality CR-Scan Raptor.
+         </p>
+      </section>
+
+      <!-- Specifications -->
+      <section class="grid grid-cols-1 md:grid-cols-2 gap-8">
+        <div class="bg-card/50 border border-border/50 rounded-3xl p-8 backdrop-blur-sm space-y-6">
+          <h2 class="text-2xl font-bold flex items-center gap-3"><Monitor class="w-6 h-6 text-primary" /> Синий лазер (Высокая точность)</h2>
+          <ul class="space-y-3 text-muted-foreground">
+            <li><strong class="text-foreground">Точность:</strong> до 0.02 мм</li>
+            <li><strong class="text-foreground">Скорость сканирования:</strong> до 60 fps</li>
+            <li><strong class="text-foreground">Рабочая дистанция:</strong> 150 мм – 400 мм</li>
+            <li><strong class="text-foreground">Размер объекта:</strong> 5 мм – 2000 мм</li>
+            <li><strong class="text-foreground">Позиционирование:</strong> По маркерам (обязательно)</li>
+            <li><strong class="text-foreground">Идеально для:</strong> Технических деталей, запчастей, реверс-инжиниринга.</li>
+          </ul>
+        </div>
+        
+        <div class="bg-card/50 border border-border/50 rounded-3xl p-8 backdrop-blur-sm space-y-6">
+          <h2 class="text-2xl font-bold flex items-center gap-3"><Lightbulb class="w-6 h-6 text-primary" /> NIR (Инфракрасный режим)</h2>
+          <ul class="space-y-3 text-muted-foreground">
+            <li><strong class="text-foreground">Точность:</strong> до 0.1 мм</li>
+            <li><strong class="text-foreground">Скорость сканирования:</strong> до 20 fps</li>
+            <li><strong class="text-foreground">Рабочая дистанция:</strong> 170 мм – 1000 мм</li>
+            <li><strong class="text-foreground">Размер объекта:</strong> 150 мм – 2000 мм</li>
+            <li><strong class="text-foreground">Позиционирование:</strong> Маркеры, Геометрия, Текстура</li>
+            <li><strong class="text-foreground">Идеально для:</strong> Лиц, людей, скульптур, крупных объектов с текстурой.</li>
+          </ul>
+        </div>
+      </section>
+
+      <!-- Limitations -->
+      <section class="space-y-8">
+        <h2 class="text-3xl font-bold text-center">Ограничения и нюансы технологии</h2>
+        <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
+          <div class="bg-card border border-border rounded-2xl p-6 shadow-sm">
+            <h3 class="font-bold mb-2">Блестящие и прозрачные поверхности</h3>
+            <p class="text-sm text-muted-foreground">Черные, зеркальные, прозрачные и глянцевые поверхности сканируются очень плохо. Для них необходимо использовать специальный матирующий 3D-спрей (он оставляет белый налет, который смывается).</p>
+          </div>
+          <div class="bg-card border border-border rounded-2xl p-6 shadow-sm">
+            <h3 class="font-bold mb-2">Использование маркеров</h3>
+            <p class="text-sm text-muted-foreground">Для гладких деталей без ярко выраженной геометрии (например, цилиндр или гладкая труба) потребуется наклейка светоотражающих точек-маркеров на сам объект для трекинга лазера.</p>
+          </div>
+          <div class="bg-card border border-border rounded-2xl p-6 shadow-sm">
+            <h3 class="font-bold mb-2">Это Mesh, а не CAD</h3>
+            <p class="text-sm text-muted-foreground">Результат сканирования — это полигональная сетка (mesh, формат STL/OBJ), а не готовая параметрическая модель (STEP). Для превращения скан-модели в CAD-деталь потребуется реверс-инжиниринг.</p>
+          </div>
+        </div>
+      </section>
+
+      <section class="text-center py-12">
+        <p class="text-xl text-muted-foreground mb-6">Услуга находится в стадии тестирования. Оставьте заявку, если у вас уже есть проект.</p>
+        <RouterLink :to="`/${$i18n.locale}/contact`" class="inline-flex items-center justify-center px-6 py-3 font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90 rounded-xl">
+          Связаться с нами
+        </RouterLink>
+      </section>
+      
+    </main>
+    <Footer />
+  </div>
+</template>
+
+<script setup lang="ts">
+import { useHead } from "@unhead/vue";
+import { Monitor, Lightbulb } from "lucide-vue-next";
+import Header from "@/components/Header.vue";
+import Footer from "@/components/Footer.vue";
+
+useHead({
+  title: "3D Сканирование",
+  meta: [
+    { name: "description", content: "Услуги 3D сканирования высокой точности" }
+  ]
+});
+</script>

+ 1 - 0
src/router/index.ts

@@ -23,6 +23,7 @@ const routes = [
       { path: "help",      name: "help",      component: () => import("@/pages/HelpCenter.vue"), meta: { title: "Help Center" } },
       { path: "guidelines", name: "guidelines", component: () => import("@/pages/Guidelines.vue"), meta: { title: "Guidelines" } },
       { path: "nuances",    name: "nuances",    component: () => import("@/pages/Nuances.vue"),    meta: { title: "Nuances" } },
+      { path: "scanning",   name: "scanning",   component: () => import("@/pages/Scanning.vue"),   meta: { title: "3D Scanning" } },
       { path: "terms",     name: "terms",     component: () => import("@/pages/Terms.vue"),      meta: { title: "Terms of Service" } },
     ]
   },

+ 1 - 0
vite.config.ts

@@ -26,6 +26,7 @@ export default defineConfig(({ mode }) => {
             '/en/privacy', '/me/privacy', '/ru/privacy', '/ua/privacy',
             '/en/terms', '/me/terms', '/ru/terms', '/ua/terms',
             '/en/careers', '/me/careers', '/ru/careers', '/ua/careers',
+            '/en/scanning', '/me/scanning', '/ru/scanning', '/ua/scanning',
           ],
           renderer: new prerender.PuppeteerRenderer({
             renderAfterDocumentEvent: 'render-event',