init
This commit is contained in:
@@ -1,58 +1,128 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="mb-6">
|
||||
<h1 class="text-2xl font-bold text-gray-900">Калькулятор 3D-печати</h1>
|
||||
<p class="mt-1 text-sm text-gray-500">Загрузите модель, выберите материал и получите мгновенный расчёт стоимости</p>
|
||||
</div>
|
||||
<HeroSection />
|
||||
|
||||
<div class="grid grid-cols-1 gap-6 lg:grid-cols-3">
|
||||
<div class="lg:col-span-2 space-y-6">
|
||||
<FileUploader />
|
||||
<MaterialPicker @open-advisor="showAdvisor = true" />
|
||||
<PrintSettings />
|
||||
|
||||
<div>
|
||||
<button
|
||||
@click="store.calculate()"
|
||||
:disabled="!store.file || !store.materialId || store.loading"
|
||||
class="btn-primary w-full sm:w-auto"
|
||||
>
|
||||
<svg v-if="store.loading" class="mr-2 h-4 w-4 animate-spin" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path>
|
||||
</svg>
|
||||
{{ store.loading ? 'Считаем...' : 'Рассчитать стоимость' }}
|
||||
</button>
|
||||
<p v-if="store.error" class="mt-2 text-sm text-red-600">{{ store.error }}</p>
|
||||
</div>
|
||||
<!-- Calculator section -->
|
||||
<section id="calculator" class="mb-12">
|
||||
<div class="mb-6">
|
||||
<h2 class="text-2xl font-bold text-gray-900">Калькулятор стоимости</h2>
|
||||
<p class="mt-1 text-sm text-gray-500">Загрузите модель, выберите материал и получите мгновенный расчёт</p>
|
||||
</div>
|
||||
|
||||
<div class="lg:col-span-1">
|
||||
<div class="sticky top-8">
|
||||
<PriceResult />
|
||||
<div v-if="!store.result" class="card text-center text-sm text-gray-400">
|
||||
<svg class="mx-auto mb-3 h-12 w-12 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 15.75V18m-7.5-6.75h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25v-.008zm2.25-4.5h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008v-.008zm2.25-4.5h.008v.008H12.75v-.008zm0 2.25h.008v.008H12.75v-.008zm0 2.25h.008v.008H12.75v-.008zm0 2.25h.008v.008H12.75v-.008zm2.25-4.5h.008v.008H15v-.008zm0 2.25h.008v.008H15v-.008zm0 2.25h.008v.008H15v-.008z" />
|
||||
</svg>
|
||||
<p>Загрузите модель и выберите материал для расчёта</p>
|
||||
<div class="grid grid-cols-1 gap-6 lg:grid-cols-3">
|
||||
<div class="lg:col-span-2 space-y-6">
|
||||
<FileUploader />
|
||||
<MaterialPicker @open-advisor="showAdvisor = true" />
|
||||
<PrintSettings />
|
||||
|
||||
<div>
|
||||
<button
|
||||
@click="store.calculate()"
|
||||
:disabled="!store.file || !store.materialId || store.loading"
|
||||
class="btn-primary w-full sm:w-auto"
|
||||
>
|
||||
<svg v-if="store.loading" class="mr-2 h-4 w-4 animate-spin" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path>
|
||||
</svg>
|
||||
{{ store.loading ? 'Считаем...' : 'Рассчитать стоимость' }}
|
||||
</button>
|
||||
<p v-if="store.error" class="mt-2 text-sm text-red-600">{{ store.error }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lg:col-span-1">
|
||||
<div class="sticky top-20">
|
||||
<PriceResult />
|
||||
<div v-if="!store.result" class="card text-center text-sm text-gray-400">
|
||||
<svg class="mx-auto mb-3 h-12 w-12 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 15.75V18m-7.5-6.75h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25v-.008zm2.25-4.5h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008v-.008zm2.25-4.5h.008v.008H12.75v-.008zm0 2.25h.008v.008H12.75v-.008zm0 2.25h.008v.008H12.75v-.008zm0 2.25h.008v.008H12.75v-.008zm2.25-4.5h.008v.008H15v-.008zm0 2.25h.008v.008H15v-.008zm0 2.25h.008v.008H15v-.008z" />
|
||||
</svg>
|
||||
<p>Загрузите модель и выберите материал для расчёта</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Features -->
|
||||
<section class="mb-12">
|
||||
<h2 class="mb-6 text-2xl font-bold text-gray-900">Как это работает</h2>
|
||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-3">
|
||||
<div class="card text-center">
|
||||
<div class="mx-auto mb-3 flex h-12 w-12 items-center justify-center rounded-xl bg-primary-100">
|
||||
<svg class="h-6 w-6 text-primary-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="mb-1 text-sm font-bold text-gray-900">Загрузите модель</h3>
|
||||
<p class="text-xs text-gray-500">STL, 3MF или OBJ файл до 50 МБ. Drag-and-drop или выбор файла.</p>
|
||||
</div>
|
||||
<div class="card text-center">
|
||||
<div class="mx-auto mb-3 flex h-12 w-12 items-center justify-center rounded-xl bg-primary-100">
|
||||
<svg class="h-6 w-6 text-primary-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 010 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 010-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="mb-1 text-sm font-bold text-gray-900">Настройте параметры</h3>
|
||||
<p class="text-xs text-gray-500">Выберите материал, заполнение, высоту слоя. AI поможет с выбором.</p>
|
||||
</div>
|
||||
<div class="card text-center">
|
||||
<div class="mx-auto mb-3 flex h-12 w-12 items-center justify-center rounded-xl bg-primary-100">
|
||||
<svg class="h-6 w-6 text-primary-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 18.75a60.07 60.07 0 0115.797 2.101c.727.198 1.453-.342 1.453-1.096V18.75M3.75 4.5v.75A.75.75 0 013 6h-.75m0 0v-.375c0-.621.504-1.125 1.125-1.125H20.25M2.25 6v9m18-10.5v.75c0 .414.336.75.75.75h.75m-1.5-1.5h.375c.621 0 1.125.504 1.125 1.125v9.75c0 .621-.504 1.125-1.125 1.125h-.375m1.5-1.5H21a.75.75 0 00-.75.75v.75m0 0H3.75m0 0h-.375a1.125 1.125 0 01-1.125-1.125V15m1.5 1.5v-.75A.75.75 0 003 15h-.75M15 10.5a3 3 0 11-6 0 3 3 0 016 0zm3 0h.008v.008H18V10.5zm-12 0h.008v.008H6V10.5z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="mb-1 text-sm font-bold text-gray-900">Получите цену</h3>
|
||||
<p class="text-xs text-gray-500">Детальная разбивка стоимости. Оформите заказ в два клика.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Latest articles -->
|
||||
<section class="mb-8">
|
||||
<div class="mb-6 flex items-center justify-between">
|
||||
<h2 class="text-2xl font-bold text-gray-900">Полезные статьи</h2>
|
||||
<router-link to="/blog" class="text-sm font-medium text-primary-600 hover:text-primary-700">
|
||||
Все статьи →
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<router-link
|
||||
v-for="article in latestArticles"
|
||||
:key="article.slug"
|
||||
:to="`/blog/${article.slug}`"
|
||||
class="card group transition-shadow hover:shadow-md"
|
||||
>
|
||||
<span class="text-xs font-medium text-primary-600">{{ article.category }}</span>
|
||||
<h3 class="mt-1 text-sm font-bold text-gray-900 group-hover:text-primary-600 transition-colors leading-snug">
|
||||
{{ article.title }}
|
||||
</h3>
|
||||
<p class="mt-1.5 text-xs text-gray-500 line-clamp-2">{{ article.description }}</p>
|
||||
</router-link>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<AiAdvisor :open="showAdvisor" @close="showAdvisor = false" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, computed } from 'vue'
|
||||
import { useCalculatorStore } from '../stores/calculator'
|
||||
import HeroSection from '../components/HeroSection.vue'
|
||||
import FileUploader from '../components/FileUploader.vue'
|
||||
import MaterialPicker from '../components/MaterialPicker.vue'
|
||||
import PrintSettings from '../components/PrintSettings.vue'
|
||||
import PriceResult from '../components/PriceResult.vue'
|
||||
import AiAdvisor from '../components/AiAdvisor.vue'
|
||||
import { articles } from '../data/articles'
|
||||
|
||||
const store = useCalculatorStore()
|
||||
const showAdvisor = ref(false)
|
||||
|
||||
const latestArticles = computed(() =>
|
||||
[...articles].sort((a, b) => b.date.localeCompare(a.date)).slice(0, 3)
|
||||
)
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user