Vue.component('warehouse-article-modal', {
template: `
Lade Kategorien...
Lade Artikel...
event.currentTarget.style.backgroundColor='#f5f5f5'"
@mouseleave="event => event.currentTarget.style.backgroundColor='#fff'">
{{ 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();
}
}
}
});