Files
filam3d/frontend/src/components/OrderForm.vue
2026-03-22 14:26:45 +03:00

229 lines
9.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="space-y-5">
<!-- Auth section -->
<div v-if="!clientStore.isAuthenticated" class="rounded-lg border border-gray-200 bg-gray-50 p-4">
<div class="flex gap-2 mb-4">
<button
@click="authMode = 'login'"
:class="['rounded-lg px-4 py-1.5 text-sm font-medium transition-colors', authMode === 'login' ? 'bg-primary-600 text-white' : 'bg-white text-gray-600 border border-gray-200']"
>Войти</button>
<button
@click="authMode = 'register'"
:class="['rounded-lg px-4 py-1.5 text-sm font-medium transition-colors', authMode === 'register' ? 'bg-primary-600 text-white' : 'bg-white text-gray-600 border border-gray-200']"
>Регистрация</button>
<button
@click="authMode = 'guest'"
:class="['rounded-lg px-4 py-1.5 text-sm font-medium transition-colors', authMode === 'guest' ? 'bg-gray-700 text-white' : 'bg-white text-gray-600 border border-gray-200']"
>Без регистрации</button>
</div>
<!-- Login form -->
<form v-if="authMode === 'login'" @submit.prevent="handleLogin" class="space-y-3">
<div>
<label class="mb-1 block text-xs font-medium text-gray-600">Email</label>
<input v-model="authForm.email" type="email" required class="input-field" placeholder="your@email.com" />
</div>
<div>
<label class="mb-1 block text-xs font-medium text-gray-600">Пароль</label>
<input v-model="authForm.password" type="password" required class="input-field" />
</div>
<p v-if="authError" class="text-sm text-red-600">{{ authError }}</p>
<button type="submit" :disabled="authLoading" class="btn-primary text-sm">
{{ authLoading ? 'Вход...' : 'Войти' }}
</button>
</form>
<!-- Register form -->
<form v-if="authMode === 'register'" @submit.prevent="handleRegister" class="space-y-3">
<div class="grid grid-cols-2 gap-3">
<div>
<label class="mb-1 block text-xs font-medium text-gray-600">Имя *</label>
<input v-model="authForm.name" required class="input-field" placeholder="Иван Петров" />
</div>
<div>
<label class="mb-1 block text-xs font-medium text-gray-600">Email *</label>
<input v-model="authForm.email" type="email" required class="input-field" placeholder="your@email.com" />
</div>
<div>
<label class="mb-1 block text-xs font-medium text-gray-600">Пароль *</label>
<input v-model="authForm.password" type="password" required minlength="6" class="input-field" />
</div>
<div>
<label class="mb-1 block text-xs font-medium text-gray-600">Телефон</label>
<input v-model="authForm.phone" class="input-field" placeholder="+79001234567" />
</div>
</div>
<div>
<label class="mb-1 block text-xs font-medium text-gray-600">Компания</label>
<input v-model="authForm.company" class="input-field" placeholder="ООО Технопарк" />
</div>
<p v-if="authError" class="text-sm text-red-600">{{ authError }}</p>
<button type="submit" :disabled="authLoading" class="btn-primary text-sm">
{{ authLoading ? 'Регистрация...' : 'Зарегистрироваться' }}
</button>
</form>
<!-- Guest info -->
<p v-if="authMode === 'guest'" class="text-sm text-gray-500">
Вы можете оформить заказ без регистрации. Отслеживание заказа будет доступно только по номеру заказа.
</p>
</div>
<!-- Logged in info -->
<div v-else class="flex items-center justify-between rounded-lg border border-green-200 bg-green-50 px-4 py-3">
<div class="flex items-center gap-2">
<svg class="h-5 w-5 text-green-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span class="text-sm font-medium text-green-800">{{ clientStore.user?.name }}</span>
<span class="text-xs text-green-600">{{ clientStore.user?.email }}</span>
</div>
<button @click="clientStore.logout()" class="text-xs text-green-700 hover:text-green-900 underline">Выйти</button>
</div>
<!-- Order form -->
<form @submit.prevent="submitOrder" class="space-y-4">
<template v-if="!clientStore.isAuthenticated">
<div>
<label class="mb-1.5 block text-sm font-medium text-gray-700">Имя *</label>
<input v-model="form.client_name" required class="input-field" placeholder="Иван Петров" />
</div>
<div>
<label class="mb-1.5 block text-sm font-medium text-gray-700">Телефон *</label>
<input v-model="form.client_phone" required class="input-field" placeholder="+79001234567" />
</div>
<div>
<label class="mb-1.5 block text-sm font-medium text-gray-700">Email</label>
<input v-model="form.client_email" type="email" class="input-field" placeholder="ivan@example.com" />
</div>
<div>
<label class="mb-1.5 block text-sm font-medium text-gray-700">Компания</label>
<input v-model="form.client_company" class="input-field" placeholder="ООО Технопарк" />
</div>
</template>
<div>
<label class="mb-1.5 block text-sm font-medium text-gray-700">Способ получения</label>
<select v-model="form.delivery_method" class="input-field">
<option value="pickup">Самовывоз</option>
<option value="delivery">Доставка</option>
</select>
</div>
<div>
<label class="mb-1.5 block text-sm font-medium text-gray-700">Комментарий</label>
<textarea v-model="form.comment" rows="3" class="input-field" placeholder="Дополнительные пожелания"></textarea>
</div>
<p v-if="error" class="text-sm text-red-600">{{ error }}</p>
<button type="submit" :disabled="loading" class="btn-primary w-full">
<svg v-if="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>
{{ loading ? 'Оформляем...' : 'Оформить заказ' }}
</button>
</form>
</div>
</template>
<script setup>
import { reactive, ref, watch } from 'vue'
import api from '../api/client'
import { useClientStore } from '../stores/client'
const props = defineProps({ calculationId: String })
const emit = defineEmits(['success'])
const clientStore = useClientStore()
const authMode = ref('login')
const authForm = reactive({ email: '', password: '', name: '', phone: '', company: '' })
const authError = ref('')
const authLoading = ref(false)
const form = reactive({
client_name: '',
client_phone: '',
client_email: '',
client_company: '',
delivery_method: 'pickup',
comment: '',
})
const loading = ref(false)
const error = ref('')
// Pre-fill form from client data
watch(() => clientStore.user, (u) => {
if (u) {
form.client_name = u.name || ''
form.client_phone = u.phone || ''
form.client_email = u.email || ''
form.client_company = u.company || ''
}
}, { immediate: true })
async function handleLogin() {
authLoading.value = true
authError.value = ''
try {
await clientStore.login(authForm.email, authForm.password)
} catch (e) {
authError.value = e.response?.data?.detail || 'Ошибка входа'
} finally {
authLoading.value = false
}
}
async function handleRegister() {
authLoading.value = true
authError.value = ''
try {
await clientStore.register({
email: authForm.email,
password: authForm.password,
name: authForm.name,
phone: authForm.phone || null,
company: authForm.company || null,
})
} catch (e) {
authError.value = e.response?.data?.detail || 'Ошибка регистрации'
} finally {
authLoading.value = false
}
}
async function submitOrder() {
loading.value = true
error.value = ''
try {
const payload = {
calculation_id: props.calculationId,
delivery_method: form.delivery_method,
comment: form.comment,
}
if (clientStore.isAuthenticated) {
payload.client_name = clientStore.user.name
payload.client_phone = clientStore.user.phone || '+70000000000'
payload.client_email = clientStore.user.email
payload.client_company = clientStore.user.company
payload.client_token = clientStore.token
} else {
payload.client_name = form.client_name
payload.client_phone = form.client_phone
payload.client_email = form.client_email
payload.client_company = form.client_company
}
const { data } = await api.post('/orders', payload)
emit('success', data)
} catch (e) {
error.value = e.response?.data?.detail || 'Ошибка оформления заказа'
} finally {
loading.value = false
}
}
</script>