// Recipe manager module import { showToast } from './utils/uiHelpers.js'; import { state } from './state/index.js'; import { initializeCommonComponents } from './common.js'; import { ImportManager } from './managers/ImportManager.js'; class RecipeManager { constructor() { this.currentPage = 1; this.pageSize = 20; this.sortBy = 'date'; this.filterParams = {}; // Initialize ImportManager this.importManager = new ImportManager(); this.init(); } init() { // Initialize event listeners this.initEventListeners(); // Load initial set of recipes this.loadRecipes(); } initEventListeners() { // Sort select const sortSelect = document.getElementById('sortSelect'); if (sortSelect) { sortSelect.addEventListener('change', () => { this.sortBy = sortSelect.value; this.loadRecipes(); }); } // Search input const searchInput = document.getElementById('searchInput'); if (searchInput) { let debounceTimeout; searchInput.addEventListener('input', () => { clearTimeout(debounceTimeout); debounceTimeout = setTimeout(() => { this.filterParams.search = searchInput.value; this.loadRecipes(); }, 300); }); } // Import button const importButton = document.querySelector('button[onclick="importRecipes()"]'); if (importButton) { importButton.onclick = (e) => { e.preventDefault(); this.importManager.showImportModal(); }; } } async loadRecipes() { try { // Show loading indicator document.body.classList.add('loading'); // Build query parameters const params = new URLSearchParams({ page: this.currentPage, page_size: this.pageSize, sort_by: this.sortBy }); // Add search filter if present if (this.filterParams.search) { params.append('search', this.filterParams.search); } // Add other filters if (this.filterParams.baseModels && this.filterParams.baseModels.length) { params.append('base_models', this.filterParams.baseModels.join(',')); } // Fetch recipes const response = await fetch(`/api/recipes?${params.toString()}`); if (!response.ok) { throw new Error(`Failed to load recipes: ${response.statusText}`); } const data = await response.json(); // Update recipes grid this.updateRecipesGrid(data); } catch (error) { console.error('Error loading recipes:', error); showToast('Failed to load recipes', 'error'); } finally { // Hide loading indicator document.body.classList.remove('loading'); } } updateRecipesGrid(data) { const grid = document.getElementById('recipeGrid'); if (!grid) return; // Check if data exists and has items if (!data.items || data.items.length === 0) { grid.innerHTML = `
`; return; } // Clear grid grid.innerHTML = ''; // Create recipe cards data.items.forEach(recipe => { const card = this.createRecipeCard(recipe); grid.appendChild(card); }); } createRecipeCard(recipe) { const card = document.createElement('div'); card.className = 'recipe-card'; card.dataset.filePath = recipe.file_path; card.dataset.title = recipe.title; card.dataset.created = recipe.created_date; console.log(recipe); // 获取 base model const baseModel = recipe.base_model || ''; // 确保 loras 数组存在 const lorasCount = recipe.loras ? recipe.loras.length : 0; // Ensure file_url exists, fallback to file_path if needed const imageUrl = recipe.file_url || (recipe.file_path ? `/loras_static/root1/preview/${recipe.file_path.split('/').pop()}` : '/loras_static/images/no-preview.png'); card.innerHTML = `