Vue.component('warehouse-article-modal', { template: `
{{ category.name }}
Lade Kategorien...
Lade Artikel...
{{ article.title }} ({{ article.articleNumber }})
{{ article.description }}
Keine Artikel entsprechen Ihrer Suche nach "{{ searchTerm }}".
Keine Artikel in der ausgewählten Kategorie gefunden.
`, data() { return { window: window, isLoadingCategories: false, // Added loading state for categories categories: [], selectedCategory: null, articles: [], searchTerm: '', isLoadingArticles: false, } }, computed: { filteredArticles() { if (!this.searchTerm) { return this.articles; } const lowerSearchTerm = this.searchTerm.toLowerCase(); // Ensure articles is an array before filtering if (!Array.isArray(this.articles)) { console.warn('Attempted to filter non-array articles:', this.articles); return []; } return this.articles.filter(article => { const titleMatch = article.title?.toLowerCase().includes(lowerSearchTerm); const articleNumberMatch = article.articleNumber?.toLowerCase().includes(lowerSearchTerm); const descriptionMatch = article.description?.toLowerCase().includes(lowerSearchTerm); return titleMatch || articleNumberMatch || descriptionMatch; }); } }, methods: { async selectCategory(category) { if (this.selectedCategory && this.selectedCategory.id === category.id) { return; } this.selectedCategory = category; this.searchTerm = ''; this.articles = []; console.log('Selected Category:', this.selectedCategory); await this.fetchArticles(category.id); }, async fetchArticles(categoryId) { if (!categoryId) return; this.isLoadingArticles = true; try { const response = await axios.post(window.TT_CONFIG.BASE_PATH + '/WarehouseArticle/getAll', { filters: { category_id: categoryId } }); // Robust check: Ensure response.data is an array if (Array.isArray(response.data)) { this.articles = response.data; } else { console.warn('Fetched articles data is not an array:', response.data); this.articles = []; // Set to empty array if not valid } console.log('Fetched Articles:', this.articles); } catch (error) { console.error("Error fetching articles:", error); this.articles = []; } finally { this.isLoadingArticles = false; } }, selectArticle(article) { console.log('Selected Article:', article); this.$emit('article-selected', article); this.$emit('close'); }, getCategoryStyle(category) { const style = {}; if (this.selectedCategory && this.selectedCategory.id === category.id) { style.backgroundColor = '#d0e0ff'; style.borderColor = '#a0c0ff'; style.fontWeight = 'bold'; style.boxShadow = '0 0 5px rgba(0, 100, 255, 0.3)'; } return style; }, hoverCategory(event, isHovering) { // Call findCategoryId safely const categoryId = this.findCategoryId(event.target.innerText); // Guard: Only proceed if categoryId was found if (categoryId === null) { // console.warn('Could not find category ID for:', event.target.innerText); return; // Stop if ID couldn't be found (e.g., categories not loaded yet) } // Rest of the hover logic... if (!event.target.dataset.categoryId) { event.target.dataset.categoryId = categoryId; } if (!this.selectedCategory || this.selectedCategory.id != categoryId) { if (isHovering) { event.target.style.backgroundColor = '#e9e9e9'; event.target.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)'; } else { event.target.style.backgroundColor = '#f9f9f9'; event.target.style.boxShadow = 'none'; } } else { if (!isHovering) { event.target.style.boxShadow = this.getCategoryStyle(this.selectedCategory).boxShadow || 'none'; event.target.style.backgroundColor = this.getCategoryStyle(this.selectedCategory).backgroundColor ||'#d0e0ff'; } } }, findCategoryId(name) { // **** GUARD ADDED HERE **** // Check if categories is an array and has items before using .find() if (!Array.isArray(this.categories) || this.categories.length === 0) { // console.warn('findCategoryId called before categories array is ready or populated.'); return null; // Return null if categories are not ready } // Now it's safe to use .find() const found = this.categories.find(cat => cat && cat.name === name); // Added check for cat existence return found ? found.id : null; } }, async mounted() { this.isLoadingCategories = true; // Set loading true before fetch try { const response = await axios.get(window.TT_CONFIG.BASE_PATH + '/WarehouseCategory/getAll'); console.log('Raw category response.data:', response.data); // Log the raw response console.log('Is response.data an array?', Array.isArray(response.data)); // Check if it's an array // **** ROBUST ASSIGNMENT **** // Ensure we assign an array, even if the response isn't one. if (Array.isArray(response.data)) { this.categories = response.data; } else if (response.data && Array.isArray(response.data.data)) { // Example: Handle common case where data is nested like { data: [...] } console.log('Assigning categories from response.data.data'); this.categories = response.data.data; } else { console.warn('Categories response.data is not an array and not handled structure:', response.data); this.categories = []; // Default to empty array if response is unexpected } console.log('Assigned this.categories:', this.categories); } catch (error) { console.error("Error fetching categories:", error); this.categories = []; // Ensure it's an array on error } finally { this.isLoadingCategories = false; // Set loading false after fetch/error } } }) Vue.component('tt-input-article', { template: `
`, props: { value: { type: [String, Number] }, label: { type: String, required: false }, apiUrl: { type: String, default: '/WarehouseArticle/autoComplete' }, placeholder: { type: String, default: '' }, items: { type: Array, default: () => [] }, sm: { type: Boolean, default: true }, row: { type: Boolean, default: false }, returnText: { type: Boolean, default: false }, emitDisplayValue: { type: Boolean, default: true }, caseInsensitive: { type: Boolean, default: false }, field: { type: Object, default: () => ({}) }, }, data() { return { window, showArticleModal: false }; }, computed: { fullApiUrl() { // Ensure the API URL has the base path return this.apiUrl.startsWith('/') ? window.TT_CONFIG.BASE_PATH + this.apiUrl : this.apiUrl; }, wrapperStyle() { return this.field && this.field.style ? this.field.style : ''; } }, methods: { openArticleModal() { this.showArticleModal = true; }, handleArticleSelected(article) { if (!article) return; // Update the value (article ID) this.$emit('input', article.id); // Update the display text (article title) if (this.emitDisplayValue) { this.$emit('displayValue', article.title); } // Force the autocomplete component to update if (this.$refs.autocomplete && typeof this.$refs.autocomplete.updateDisplayValue === 'function') { this.$refs.autocomplete.displayValue = article.title; } }, updateValue(val) { this.$emit('input', val); }, updateDisplayValue(val) { if (this.emitDisplayValue) { this.$emit('displayValue', val); } }, clear() { if (this.$refs.autocomplete && typeof this.$refs.autocomplete.clear === 'function') { this.$refs.autocomplete.clear(); } } } });