diff --git a/frontend/src/views/OLAPConstructor.vue b/frontend/src/views/OLAPConstructor.vue index 4af52ac..4febf4c 100644 --- a/frontend/src/views/OLAPConstructor.vue +++ b/frontend/src/views/OLAPConstructor.vue @@ -106,101 +106,107 @@
-
+
+
+ +
+ + +
- -
- - + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + + +
- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
+ + + +
+
+
+
+
+

Выбор ресторанов

+ +
+
+
+ + + + +
+
+
+
+
+
+ + + +
+
+

{{ rest.name }}

+

{{ rest.host }}

+
+
+
+ + + +
+
+
+ Рестораны не найдены +
+
+
+ + +
+
+
+
+
+ + + +
+
+
+
+
+

Подключение к БД

+ +
+
+
+ + + + +
+
+
+
+
+

{{ conn.name }}

+

{{ conn.type }} | {{ conn.host }}:{{ conn.port }}/{{ conn.database }}

+
+
+ + + +
+
+
+ Подключения не найдены +
+
+
+ + +
+
+
+
+
@@ -395,7 +508,7 @@ import { useNotification } from '@/composables/useNotification' const { showNotification } = useNotification() -// Типы (без изменений) +// Типы interface ApiColumn { fieldKey: string fieldKeyNormal: string @@ -456,7 +569,23 @@ interface IikoConfig { filters: Record } -// Refs +interface Restaurant { + id: number + name: string + host: string +} + +interface DbConnection { + id: number + name: string + type: string + host: string + port: number + database: string + user: string +} + +// Состояния const columnsData = ref([]) const loading = ref(true) const error = ref(null) @@ -477,22 +606,126 @@ const reportType = ref<'SALES' | 'DELIVERIES' | 'TRANSACTIONS'>('SALES') const buildSummary = ref(false) const searchQuery = ref('') const activeTab = ref<'table' | 'sql'>('table') +const collapsed = ref({ number: false, category: false, filter: false }) -// Состояние сворачивания секций -const collapsed = ref({ - number: false, - category: false, - filter: false +const queryName = ref('') // имя запроса +const selectedRestaurants = ref([]) // выбранные рестораны +const selectedDbConnection = ref(null) // выбранное подключение к БД + +// Модалка ресторанов +const restaurantModal = ref({ + show: false, + search: '' }) +const restaurantsList = ref([]) +const tempSelectedRestaurants = ref([]) + +// Модалка подключения к БД +const dbConnectionModal = ref({ + show: false, + search: '' +}) +const dbConnectionsList = ref([]) +const tempSelectedDbConnection = ref(null) + +// Вспомогательные вычисляемые свойства для модалок +const filteredRestaurantsList = computed(() => { + if (!restaurantModal.value.search.trim()) return restaurantsList.value + const lower = restaurantModal.value.search.toLowerCase() + return restaurantsList.value.filter(r => + r.name.toLowerCase().includes(lower) || r.host.toLowerCase().includes(lower) + ) +}) + +const filteredDbConnectionsList = computed(() => { + if (!dbConnectionModal.value.search.trim()) return dbConnectionsList.value + const lower = dbConnectionModal.value.search.toLowerCase() + return dbConnectionsList.value.filter(c => c.name.toLowerCase().includes(lower)) +}) + +// Функции для ресторанов +const openRestaurantModal = async () => { + await loadRestaurants() + // Копируем текущие выбранные рестораны во временный массив + tempSelectedRestaurants.value = [...selectedRestaurants.value] + restaurantModal.value.search = '' + restaurantModal.value.show = true +} + +const closeRestaurantModal = () => { + restaurantModal.value.show = false +} + +const isRestaurantSelected = (rest: Restaurant) => { + return tempSelectedRestaurants.value.some(r => r.id === rest.id) +} + +const toggleRestaurantSelection = (rest: Restaurant) => { + const idx = tempSelectedRestaurants.value.findIndex(r => r.id === rest.id) + if (idx === -1) { + tempSelectedRestaurants.value.push(rest) + } else { + tempSelectedRestaurants.value.splice(idx, 1) + } +} + +const confirmRestaurants = () => { + selectedRestaurants.value = [...tempSelectedRestaurants.value] + closeRestaurantModal() + showNotification('Рестораны выбраны', 'success') +} + +// Функции для подключения к БД +const openDbConnectionModal = async () => { + await loadDbConnections() + tempSelectedDbConnection.value = selectedDbConnection.value ? { ...selectedDbConnection.value } : null + dbConnectionModal.value.search = '' + dbConnectionModal.value.show = true +} + +const closeDbConnectionModal = () => { + dbConnectionModal.value.show = false +} + +const selectDbConnection = (conn: DbConnection) => { + tempSelectedDbConnection.value = conn +} + +const confirmDbConnection = () => { + selectedDbConnection.value = tempSelectedDbConnection.value ? { ...tempSelectedDbConnection.value } : null + closeDbConnectionModal() + showNotification('Подключение к БД выбрано', 'success') +} + +// Загрузка данных для модалок +const loadRestaurants = async () => { + try { + const res = await fetch('/api/admin/restaurants') + if (!res.ok) throw new Error('Ошибка загрузки ресторанов') + const data = await res.json() + restaurantsList.value = data + } catch (err: any) { + showNotification('Не удалось загрузить список ресторанов', 'error') + } +} + +const loadDbConnections = async () => { + try { + const res = await fetch('/api/admin/database-connections') + if (!res.ok) throw new Error('Ошибка загрузки подключений') + const data = await res.json() + dbConnectionsList.value = data + } catch (err: any) { + showNotification('Не удалось загрузить список подключений к БД', 'error') + } +} const toggleSection = (section: 'number' | 'category' | 'filter') => { collapsed.value[section] = !collapsed.value[section] } -// Модалка сброса const resetModal = ref({ show: false }) -// Drag & drop state let draggedItem: AvailableField | null = null let draggedFromSidebar = true const dragOverZone = ref(null) @@ -784,6 +1017,9 @@ const confirmReset = () => { tableNameTouched.value = false buildSummary.value = false searchQuery.value = '' + queryName.value = '' + selectedRestaurants.value = [] + selectedDbConnection.value = null showNotification('Все настройки сброшены', 'success') }