264 lines
9.3 KiB
Vue
264 lines
9.3 KiB
Vue
<template>
|
||
<div class="grid">
|
||
<div class="col-12">
|
||
<div class="card">
|
||
<h5>Генерация отчёта</h5>
|
||
<p>Заполните форму для создания нового отчёта на основе собранных данных.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="col-12 lg:col-8">
|
||
<div class="card">
|
||
<form @submit.prevent="handleGenerate" class="p-fluid">
|
||
<div class="grid">
|
||
<div class="col-12">
|
||
<div class="field">
|
||
<label for="query">Тема исследования *</label>
|
||
<InputText id="query" v-model="formData.query" :class="{ 'p-invalid': errors.query }" placeholder="Введите тему для исследования" size="large" />
|
||
<small v-if="errors.query" class="p-error">{{ errors.query }}</small>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="col-12 md:col-6">
|
||
<div class="field">
|
||
<label for="lang">Язык отчёта</label>
|
||
<Dropdown id="lang" v-model="formData.lang" :options="langOptions" optionLabel="label" optionValue="value" placeholder="Выберите язык" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="col-12 md:col-6">
|
||
<div class="field">
|
||
<label for="report_type">Тип отчёта</label>
|
||
<Dropdown id="report_type" v-model="formData.report_type" :options="reportTypeOptions" optionLabel="label" optionValue="value" placeholder="Выберите тип" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="col-12 md:col-6">
|
||
<div class="field">
|
||
<label for="depth">Глубина исследования</label>
|
||
<Slider id="depth" v-model.number="formData.depth" :min="1" :max="5" :step="1" :disabled="false" />
|
||
<small class="text-600">Текущее значение: {{ formData.depth }}</small>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="col-12 md:col-6">
|
||
<div class="field">
|
||
<label for="breadth">Широта исследования</label>
|
||
<Slider id="breadth" v-model.number="formData.breadth" :min="2" :max="10" :step="1" :disabled="false" />
|
||
<small class="text-600">Текущее значение: {{ formData.breadth }}</small>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="col-12">
|
||
<div class="flex gap-2">
|
||
<Button type="submit" label="Сгенерировать отчёт" icon="pi pi-file-pdf" :loading="loading" :disabled="loading" size="large" />
|
||
<Button type="button" label="Очистить форму" icon="pi pi-refresh" severity="secondary" @click="resetForm" :disabled="loading" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="col-12 lg:col-4">
|
||
<div class="card">
|
||
<h6>Информация о генерации</h6>
|
||
<div class="flex flex-column gap-3">
|
||
<div class="flex align-items-center gap-2">
|
||
<i class="pi pi-info-circle text-blue-500"></i>
|
||
<span class="text-sm">Отчёт будет создан с помощью AI-исследования</span>
|
||
</div>
|
||
<div class="flex align-items-center gap-2">
|
||
<i class="pi pi-clock text-orange-500"></i>
|
||
<span class="text-sm">Время генерации: до 5 минут</span>
|
||
</div>
|
||
<div class="flex align-items-center gap-2">
|
||
<i class="pi pi-download text-green-500"></i>
|
||
<span class="text-sm">PDF-файл будет автоматически скачан</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card mt-3">
|
||
<h6>Параметры исследования</h6>
|
||
<div class="flex flex-column gap-2">
|
||
<div class="flex align-items-center gap-2">
|
||
<i class="pi pi-search text-purple-500"></i>
|
||
<span class="text-sm">Глубина: детальность анализа</span>
|
||
</div>
|
||
<div class="flex align-items-center gap-2">
|
||
<i class="pi pi-globe text-cyan-500"></i>
|
||
<span class="text-sm">Широта: количество источников</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card mt-3">
|
||
<h6>Типы отчётов</h6>
|
||
<div class="flex flex-column gap-2">
|
||
<div class="flex align-items-center gap-2">
|
||
<i class="pi pi-file-pdf text-red-500"></i>
|
||
<span class="text-sm">Отчёт - полное исследование</span>
|
||
</div>
|
||
<div class="flex align-items-center gap-2">
|
||
<i class="pi pi-question-circle text-blue-500"></i>
|
||
<span class="text-sm">Ответ - краткий ответ на вопрос</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import ReportService from '@/service/ReportService.js';
|
||
import { useToast } from 'primevue/usetoast';
|
||
import { onMounted, reactive, ref } from 'vue';
|
||
import { useRouter } from 'vue-router';
|
||
|
||
const router = useRouter();
|
||
const toast = useToast();
|
||
|
||
// Реактивные данные
|
||
const loading = ref(false);
|
||
|
||
// Данные формы
|
||
const formData = reactive({
|
||
query: '',
|
||
lang: 'ru',
|
||
depth: 1,
|
||
breadth: 2,
|
||
report_type: 'report'
|
||
});
|
||
|
||
// Ошибки валидации
|
||
const errors = reactive({
|
||
query: null
|
||
});
|
||
|
||
// Опции
|
||
const langOptions = [
|
||
{ label: 'Русский', value: 'ru' },
|
||
{ label: 'English', value: 'en' }
|
||
];
|
||
|
||
const reportTypeOptions = [
|
||
{ label: 'Отчёт', value: 'report' },
|
||
{ label: 'Ответ', value: 'answer' }
|
||
];
|
||
|
||
// Методы
|
||
const validateForm = () => {
|
||
// Очистка предыдущих ошибок
|
||
Object.keys(errors).forEach((key) => (errors[key] = null));
|
||
|
||
let isValid = true;
|
||
|
||
if (!formData.query.trim()) {
|
||
errors.query = 'Тема исследования обязательна';
|
||
isValid = false;
|
||
}
|
||
|
||
return isValid;
|
||
};
|
||
|
||
const handleGenerate = async () => {
|
||
if (!validateForm()) {
|
||
toast.add({
|
||
severity: 'error',
|
||
summary: 'Ошибка валидации',
|
||
detail: 'Пожалуйста, исправьте ошибки в форме',
|
||
life: 3000
|
||
});
|
||
return;
|
||
}
|
||
|
||
loading.value = true;
|
||
|
||
try {
|
||
// Подготовка данных для API
|
||
const reportData = {
|
||
query: formData.query.trim(),
|
||
lang: formData.lang,
|
||
depth: formData.depth,
|
||
breadth: formData.breadth,
|
||
report_type: formData.report_type
|
||
};
|
||
|
||
// Генерируем и скачиваем отчёт
|
||
await ReportService.generateAndDownloadReport(reportData);
|
||
|
||
toast.add({
|
||
severity: 'success',
|
||
summary: 'Отчёт сгенерирован',
|
||
detail: 'PDF-файл с отчётом скачан',
|
||
life: 5000
|
||
});
|
||
|
||
// Очищаем форму после успешной генерации
|
||
resetForm();
|
||
} catch (error) {
|
||
console.error('Ошибка генерации отчёта:', error);
|
||
toast.add({
|
||
severity: 'error',
|
||
summary: 'Ошибка',
|
||
detail: ReportService.handleError(error),
|
||
life: 5000
|
||
});
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
};
|
||
|
||
const resetForm = () => {
|
||
Object.assign(formData, {
|
||
query: '',
|
||
lang: 'ru',
|
||
depth: 3,
|
||
breadth: 5,
|
||
report_type: 'report'
|
||
});
|
||
|
||
Object.keys(errors).forEach((key) => (errors[key] = null));
|
||
};
|
||
|
||
// Инициализация
|
||
onMounted(() => {
|
||
// Форма уже инициализирована значениями по умолчанию
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
.p-fluid .field {
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.card {
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.text-sm {
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
.flex {
|
||
display: flex;
|
||
}
|
||
|
||
.flex-column {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.gap-2 {
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.gap-3 {
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.align-items-center {
|
||
align-items: center;
|
||
}
|
||
</style>
|