szervíz rögzítés külső szemmel

This commit is contained in:
Roo
2026-06-18 00:04:42 +00:00
parent 127b130401
commit 404d04c56b
10 changed files with 524 additions and 14 deletions

View File

@@ -1846,7 +1846,7 @@ const brandHighlightIndex = ref(0)
const modelHighlightIndex = ref(0)
function onBrandInput() {
if (!form.brand) { showBrandSuggestions = false; return }
if (!form.brand) { showBrandSuggestions.value = false; return }
// Normalize search query: uppercase, remove spaces for matching
const q = form.brand.toUpperCase().replace(/\s+/g, '')
const all = catalogStore.brands || []

View File

@@ -278,12 +278,12 @@
</div>
</div>
<!-- Level 1: Iparág/Főcsoport (children of CHECKED Level 0 + universal Level 1) -->
<div v-if="allLevel1Categories.length > 0" class="mb-3 ml-4 pl-3 border-l-2 border-sf-accent/20">
<!-- Level 1: Iparág/Főcsoport (children of CHECKED Level 0) -->
<div v-if="vehicleLevel1Categories.length > 0" class="mb-3 ml-4 pl-3 border-l-2 border-sf-accent/20">
<p class="text-xs font-semibold text-slate-500 uppercase tracking-wider mb-2">{{ t('provider.level1Label') }}</p>
<div class="flex flex-wrap gap-2">
<label
v-for="l1 in allLevel1Categories"
v-for="l1 in vehicleLevel1Categories"
:key="l1.id"
class="inline-flex items-center gap-1.5 rounded-lg border border-slate-200 px-3 py-1.5 text-xs font-medium text-slate-600 transition-all hover:border-sf-accent/40 hover:bg-sf-accent/5 cursor-pointer"
:class="{ 'border-sf-accent bg-sf-accent/10 text-sf-accent': selectedCategoryIds.includes(l1.id) }"
@@ -298,6 +298,35 @@
</label>
</div>
</div>
<!-- Universal Level 1: Iparágak és Univerzális Szolgáltatások (independent of Level 0) -->
<div v-if="universalLevel1Categories.length > 0" class="mb-3 mt-4 pt-3 border-t-2 border-dashed border-amber-200">
<div class="flex items-center gap-2 mb-3">
<div class="flex h-6 w-6 items-center justify-center rounded-full bg-amber-50 text-amber-500">
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
</svg>
</div>
<span class="text-sm font-bold text-slate-700">{{ t('categories.universal_title') }}</span>
</div>
<p class="text-xs text-slate-400 mb-2">{{ t('categories.universal_hint') }}</p>
<div class="flex flex-wrap gap-2">
<label
v-for="l1 in universalLevel1Categories"
:key="l1.id"
class="inline-flex items-center gap-1.5 rounded-lg border border-amber-200 px-3 py-1.5 text-xs font-medium text-slate-600 transition-all hover:border-amber-400 hover:bg-amber-50 cursor-pointer"
:class="{ 'border-amber-500 bg-amber-50 text-amber-700 font-semibold': selectedCategoryIds.includes(l1.id) }"
>
<input
type="checkbox"
:checked="selectedCategoryIds.includes(l1.id)"
@change="toggleCategory(l1.id)"
class="h-3.5 w-3.5 rounded border-amber-300 text-amber-500 focus:ring-amber-300"
/>
{{ l1.name_hu || l1.key }}
</label>
</div>
</div>
</div>
<!-- -->
@@ -447,7 +476,7 @@
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { ref, reactive, computed, onMounted, watch, watchEffect } from 'vue'
import { useI18n } from 'vue-i18n'
import api from '@/api/axios'
@@ -559,14 +588,15 @@ const level0Categories = computed(() => {
return categoryTree.value.filter(c => c.level === 0)
})
// ── Computed: All visible Level 1 categories ──
// Shows Level 1 children of checked Level 0 parents.
const allLevel1Categories = computed(() => {
// ── Computed: Vehicle-specific Level 1 categories ──
// Shows Level 1 children of CHECKED Level 0 parents only.
const vehicleLevel1Categories = computed(() => {
const checkedL0Ids = new Set(selectedCategoryIds.value)
const result: CategoryTreeNode[] = []
for (const l0 of level0Categories.value) {
if (l0.children.length > 0 && checkedL0Ids.has(l0.id)) {
for (const l1 of l0.children) {
// Avoid duplicates if same L1 appears under multiple L0
if (!result.some(r => r.id === l1.id)) {
result.push(l1)
}
@@ -576,6 +606,14 @@ const allLevel1Categories = computed(() => {
return result
})
// ── Computed: Universal Level 1 categories ──
// Level 1 categories that are root nodes (parent_id IS NULL) in the tree.
// These are independent of any vehicle type and always visible.
// Examples: "Üzemanyag és Töltőállomás", "Étel és Ital", "Szállás"
const universalLevel1Categories = computed(() => {
return categoryTree.value.filter(c => c.level === 1)
})
// ── Computed ──
const isFormValid = computed(() => {
return form.name.trim().length >= 2
@@ -909,6 +947,14 @@ onMounted(() => {
fetchCategories()
loadCategoryTree()
})
// 🔍 P0 Debug: Universal Level 1 categories count verification
watchEffect(() => {
console.log(`[ProviderQuickAddModal] universalLevel1Categories count: ${universalLevel1Categories.value.length}`)
if (universalLevel1Categories.value.length > 0) {
console.log(`[ProviderQuickAddModal] Universal categories:`, universalLevel1Categories.value.map(c => c.name_hu || c.name_en))
}
})
</script>
<style scoped>

View File

@@ -1349,6 +1349,8 @@ export default {
// ── Categories (Hybrid Category UI) ────────────────────────────────
categories: {
universal_title: 'Universal Services',
universal_hint: 'Vehicle-independent infrastructure',
block_a_title: 'Basic Categories (Vehicle & Industry)',
block_b_title: 'Specific Tasks & Tags',
search_placeholder: 'Search for a service, or type a new one (Enter)...',

View File

@@ -1349,6 +1349,8 @@ export default {
// ── Categories (Hybrid Category UI) ────────────────────────────────
categories: {
universal_title: 'Univerzális Szolgáltatások',
universal_hint: 'Járműtípustól független infrastruktúra',
block_a_title: 'Alap kategóriák (Jármű és Iparág)',
block_b_title: 'Specifikus feladatok és címkék',
search_placeholder: 'Keress szolgáltatást, vagy írj be újat (Enter)...',

View File

@@ -44,6 +44,17 @@
class="absolute right-0 top-full mt-2 w-56 z-50 rounded-xl border border-white/10 bg-[#04151F]/95 backdrop-blur-xl shadow-2xl shadow-black/40 overflow-hidden"
>
<div class="py-1">
<!-- Vezérlőpult (Dashboard) -->
<button
@click="navigateToDashboard"
class="flex w-full items-center gap-3 px-4 py-2.5 text-sm text-white/80 transition-all duration-150 hover:bg-white/5 hover:text-white"
>
<svg class="w-4 h-4 text-white/40" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
</svg>
{{ t('header.dashboard') }}
</button>
<!-- Járművek -->
<button
@click="navigateToCard('vehicles')"
@@ -144,10 +155,16 @@ function navigateToCard(cardId: string) {
}
}
// ── Open external Service Finder page in new tab ───────────────────
// ── Navigate to Service Finder page (same tab) ─────────────────────
function openExternalServiceFinder() {
isHamburgerOpen.value = false
window.open('https://app.servicefinder.hu/dashboard/service-finder', '_blank', 'noopener,noreferrer')
router.push('/dashboard/service-finder')
}
// ── Navigate to Dashboard homepage ─────────────────────────────────
function navigateToDashboard() {
isHamburgerOpen.value = false
router.push('/dashboard')
}
// ── Close hamburger on outside click ──────────────────────────────

View File

@@ -442,11 +442,11 @@ const isSearchModalOpen = ref(false)
const isSfQuickAddOpen = ref(false)
/**
* Opens the external Service Finder page in a new tab.
* Navigates to the Service Finder page in the same tab.
* Used by the card click and the "Tervezett karbantartás" button.
*/
function openExternalServiceFinder() {
window.open('https://app.servicefinder.hu/dashboard/service-finder', '_blank', 'noopener,noreferrer')
router.push('/dashboard/service-finder')
}
/**