init
This commit is contained in:
82
frontend/src/components/MaterialPicker.vue
Normal file
82
frontend/src/components/MaterialPicker.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div class="card">
|
||||
<div class="mb-4 flex items-center justify-between">
|
||||
<h2 class="text-lg font-semibold text-gray-900">2. Выберите материал</h2>
|
||||
<button @click="$emit('openAdvisor')" class="btn-secondary !py-1.5 !px-3 !text-xs">
|
||||
<svg class="mr-1.5 h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z" />
|
||||
</svg>
|
||||
Помочь выбрать
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-for="(label, cat) in categories" :key="cat" class="mb-5 last:mb-0">
|
||||
<h3 class="mb-2.5 text-xs font-semibold uppercase tracking-wider text-gray-500">{{ label }}</h3>
|
||||
<div class="grid grid-cols-1 gap-2.5 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<button
|
||||
v-for="mat in materialsByCategory(cat)"
|
||||
:key="mat.id"
|
||||
@click="selectMaterial(mat.id)"
|
||||
:class="[
|
||||
'flex flex-col rounded-lg border-2 p-3.5 text-left transition-all',
|
||||
store.materialId === mat.id
|
||||
? 'border-primary-500 bg-primary-50 ring-1 ring-primary-500'
|
||||
: 'border-gray-200 hover:border-gray-300 hover:bg-gray-50',
|
||||
]"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-sm font-semibold text-gray-900">{{ mat.name }}</span>
|
||||
<span class="text-xs font-medium text-gray-500">{{ mat.price_per_gram }} ₽/г</span>
|
||||
</div>
|
||||
<p class="mt-1 text-xs leading-relaxed text-gray-500">{{ mat.description }}</p>
|
||||
<div class="mt-2 flex flex-wrap gap-1.5">
|
||||
<span v-if="mat.properties.food_safe" class="inline-flex items-center rounded-full bg-green-100 px-2 py-0.5 text-[10px] font-medium text-green-700">
|
||||
Food safe
|
||||
</span>
|
||||
<span class="inline-flex items-center rounded-full bg-gray-100 px-2 py-0.5 text-[10px] font-medium text-gray-600">
|
||||
{{ mat.properties.max_temp_c }}°C
|
||||
</span>
|
||||
<span class="inline-flex items-center rounded-full bg-gray-100 px-2 py-0.5 text-[10px] font-medium text-gray-600">
|
||||
{{ strengthLabel(mat.properties.strength) }}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted } from 'vue'
|
||||
import { useCalculatorStore } from '../stores/calculator'
|
||||
import { useMaterialsStore } from '../stores/materials'
|
||||
|
||||
defineEmits(['openAdvisor'])
|
||||
|
||||
const store = useCalculatorStore()
|
||||
const materialsStore = useMaterialsStore()
|
||||
const { categories } = materialsStore
|
||||
|
||||
onMounted(() => materialsStore.fetchMaterials())
|
||||
|
||||
function materialsByCategory(cat) {
|
||||
return materialsStore.materials.filter((m) => m.category === cat)
|
||||
}
|
||||
|
||||
function selectMaterial(id) {
|
||||
store.materialId = id
|
||||
store.result = null
|
||||
}
|
||||
|
||||
const strengthLabels = {
|
||||
low: 'Низкая',
|
||||
medium: 'Средняя',
|
||||
high: 'Высокая',
|
||||
very_high: 'Очень высокая',
|
||||
extreme: 'Экстремальная',
|
||||
}
|
||||
|
||||
function strengthLabel(val) {
|
||||
return strengthLabels[val] || val
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user