index.html 15.2 KB
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Product Search - for Shoplazza</title>
    <link rel="stylesheet" href="/static/css/style.css">
    <style>
        .suggestions-list {
            position: absolute;
            top: 100%;
            left: 0;
            right: 0;
            background: white;
            border: 1px solid #ddd;
            border-radius: 4px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
            max-height: 300px;
            overflow-y: auto;
            z-index: 1000;
            margin-top: 2px;
        }
        .suggestion-item {
            padding: 10px 15px;
            cursor: pointer;
            border-bottom: 1px solid #f0f0f0;
            transition: background-color 0.2s;
        }
        .suggestion-item:hover,
        .suggestion-item.highlighted {
            background-color: #f5f5f5;
        }
        .suggestion-item:last-child {
            border-bottom: none;
        }
        .suggestion-text {
            font-size: 14px;
            color: #333;
        }
        .suggestion-meta {
            font-size: 12px;
            color: #999;
            margin-top: 2px;
        }
    </style>
</head>
<body>
    <div class="page-container">
        <!-- Header -->
        <header class="top-header">
            <div class="header-left">
                <span class="logo">Product</span>
                <span class="product-count" id="productCount">0 products found</span>
            </div>
            <div class="header-right">
                <button class="fold-btn" onclick="toggleFilters()">Fold</button>
            </div>
        </header>

        <!-- Search Bar -->
        <div class="search-bar">
            <div class="tenant-input-wrapper">
                <label for="langSelect">lang:</label>
                <select id="langSelect">
                    <option value="zh" selected>zh</option>
                    <option value="en">en</option>
                    <option value="ru">ru</option>
                    <option value="es">es</option>
                    <option value="fr">fr</option>
                    <option value="de">de</option>
                    <option value="it">it</option>
                    <option value="ja">ja</option>
                </select>
            </div>
            <div class="tenant-input-wrapper">
                <label for="tenantInput">tenant ID:</label>
                <input type="text" id="tenantInput" placeholder="请输入租户ID" value="162">
            </div>
            <div class="tenant-input-wrapper">
                <label for="skuFilterDimension">sku_filter_dimension:</label>
                <input type="text" id="skuFilterDimension" placeholder="SKU筛选维度" value="color">
            </div>
            <div class="search-input-wrapper" style="position: relative;">
                <input type="text" id="searchInput" placeholder="输入搜索关键词... (支持中文、英文、俄文)"
                       onkeypress="handleKeyPress(event)" oninput="handleSearchInput(event)">
                <div id="suggestionsList" class="suggestions-list" style="display: none;"></div>
            </div>
            <button onclick="performSearch()" class="search-btn">Search</button>
        </div>

        <!-- Filter Section -->
        <div class="filter-section" id="filterSection">
            <!-- Category Filter (一级分类) -->
            <div class="filter-row">
                <div class="filter-label">Category:</div>
                <div class="filter-tags" id="category1Tags"></div>
            </div>

            <!-- Sub Category Filter (二级分类) -->
            <div class="filter-row">
                <div class="filter-label">Sub Category:</div>
                <div class="filter-tags" id="category2Tags"></div>
            </div>

            <!-- Third Category Filter (三级分类) -->
            <div class="filter-row">
                <div class="filter-label">Third Category:</div>
                <div class="filter-tags" id="category3Tags"></div>
            </div>

            <!-- Color Filter -->
            <div class="filter-row">
                <div class="filter-label">Color:</div>
                <div class="filter-tags" id="colorTags"></div>
            </div>

            <!-- Size Filter -->
            <div class="filter-row">
                <div class="filter-label">Size:</div>
                <div class="filter-tags" id="sizeTags"></div>
            </div>

            <!-- Material Filter -->
            <div class="filter-row">
                <div class="filter-label">Material:</div>
                <div class="filter-tags" id="materialTags"></div>
            </div>

            <!-- Dropdown Filters -->
            <div class="filter-row">
                <div class="filter-label">Others:</div>
                <div class="filter-dropdowns">
                    <select id="priceFilter" onchange="handlePriceFilter(this.value)">
                        <option value="">Price</option>
                        <option value="0-50">0-50</option>
                        <option value="50-100">50-100</option>
                        <option value="100-200">100-200</option>
                        <option value="200+">200+</option>
                    </select>
                    <select id="timeFilter" onchange="handleTimeFilter(this.value)">
                        <option value="">Listing Time</option>
                        <option value="today">Today</option>
                        <option value="week">This Week</option>
                        <option value="month">This Month</option>
                        <option value="3months">Last 3 Months</option>
                        <option value="6months">Last 6 Months</option>
                    </select>
                    <button class="clear-filters-btn" onclick="clearAllFilters()" style="display: none;" id="clearFiltersBtn">Clear Filters</button>
                </div>
            </div>
        </div>

        <!-- Sort Section -->
        <div class="sort-section">
            <button class="sort-btn active" data-sort="" onclick="setSortByDefault()">By default</button>
            <button class="sort-btn" data-sort="create_time">
                By New Products
                <span class="sort-arrows">
                    <span class="arrow-up" data-field="create_time" data-order="desc" onclick="sortByField('create_time', 'desc')"></span>
                    <span class="arrow-down" data-field="create_time" data-order="asc" onclick="sortByField('create_time', 'asc')"></span>
                </span>
            </button>
            <button class="sort-btn" data-sort="price">
                By Price
                <span class="sort-arrows">
                    <span class="arrow-up" data-field="price" data-order="asc" onclick="sortByField('price', 'asc')"></span>
                    <span class="arrow-down" data-field="price" data-order="desc" onclick="sortByField('price', 'desc')"></span>
                </span>
            </button>
            <button class="sort-btn" data-sort="sales">
                By Sales
                <span class="sort-arrows">
                    <span class="arrow-up" data-field="sales" data-order="desc" onclick="sortByField('sales', 'desc')"></span>
                    <span class="arrow-down" data-field="sales" data-order="asc" onclick="sortByField('sales', 'asc')"></span>
                </span>
            </button>
            
            <div class="sort-right">
                <select id="resultSize" onchange="performSearch()">
                    <option value="20">20 per page</option>
                    <option value="50" selected>50 per page</option>
                    <option value="100">100 per page</option>
                    <option value="200">200 per page</option>
                </select>
            </div>
        </div>

        <!-- Loading -->
        <div id="loading" class="loading" style="display: none;">
            <div class="spinner"></div>
            <p>Loading...</p>
        </div>

        <!-- Product Grid -->
        <div class="product-grid" id="productGrid"></div>

        <!-- Pagination -->
        <div class="pagination" id="pagination" style="display: none;"></div>

        <!-- Debug Info -->
        <details class="debug-info">
            <summary>调试信息</summary>
            <div id="debugInfo"></div>
        </details>
    </div>

    <footer>
        <p>SearchEngine © 2025 | API: <span id="apiUrl">Loading...</span></p>
    </footer>

    <script src="/static/js/app.js?v=3.2"></script>
    <script>
        // 自动补全功能
        const SUGGEST_API = 'http://120.76.41.98:5003/suggest';
        const LANG_OPTIONS = ['zh', 'en', 'ru', 'es', 'fr', 'de', 'it', 'ja'];
        let debounceTimer = null;
        let currentSuggestions = [];
        let selectedIndex = -1;
        let abortController = null;

        // 读取当前语言,默认 zh
        function getSelectedLang() {
            const langSelect = document.getElementById('langSelect');
            if (!langSelect) return 'zh';
            return langSelect.value || 'zh';
        }

        // 初始化语言下拉,尝试使用浏览器语言(匹配到列表才生效)
        (function initLangSelect() {
            const langSelect = document.getElementById('langSelect');
            if (!langSelect) return;
            const browserLang = (navigator.language || '').slice(0, 2).toLowerCase();
            if (LANG_OPTIONS.includes(browserLang)) {
                langSelect.value = browserLang;
            } else {
                langSelect.value = 'zh';
            }
        })();

        // 防抖函数
        function debounce(func, wait) {
            return function(...args) {
                clearTimeout(debounceTimer);
                debounceTimer = setTimeout(() => func.apply(this, args), wait);
            };
        }

        // 获取建议
        async function fetchSuggestions(query) {
            if (!query || query.trim().length === 0) {
                hideSuggestions();
                return;
            }

            // 取消之前的请求
            if (abortController) {
                abortController.abort();
            }
            abortController = new AbortController();

            try {
                const url = new URL(SUGGEST_API);
                url.searchParams.set('query', query);
                url.searchParams.set('lang', getSelectedLang());
                url.searchParams.set('limit', '40');

                const response = await fetch(url.toString(), {
                    signal: abortController.signal,
                    headers: {
                        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
                        'Referer': window.location.origin + '/'
                    }
                });

                if (!response.ok) {
                    throw new Error('请求失败');
                }

                const data = await response.json();
                if (data.status === 'success' && data.suggestions) {
                    currentSuggestions = data.suggestions;
                    showSuggestions(data.suggestions);
                } else {
                    hideSuggestions();
                }
            } catch (error) {
                if (error.name !== 'AbortError') {
                    console.error('获取建议失败:', error);
                    hideSuggestions();
                }
            }
        }

        // 显示建议列表
        function showSuggestions(suggestions) {
            const list = document.getElementById('suggestionsList');
            if (!suggestions || suggestions.length === 0) {
                hideSuggestions();
                return;
            }

            list.innerHTML = '';
            suggestions.forEach((item, index) => {
                const div = document.createElement('div');
                div.className = 'suggestion-item';
                div.dataset.index = index;
                div.innerHTML = `
                    <div class="suggestion-text">${escapeHtml(item.canon)}</div>
                    <div class="suggestion-meta">${item.entry_type} | ${item.canon_freq}</div>
                `;
                div.onclick = () => selectSuggestion(item.canon);
                div.onmouseenter = () => {
                    selectedIndex = index;
                    updateHighlight();
                };
                list.appendChild(div);
            });

            list.style.display = 'block';
            selectedIndex = -1;
        }

        // 隐藏建议列表
        function hideSuggestions() {
            const list = document.getElementById('suggestionsList');
            list.style.display = 'none';
            currentSuggestions = [];
            selectedIndex = -1;
        }

        // 选择建议
        function selectSuggestion(text) {
            const input = document.getElementById('searchInput');
            input.value = text;
            hideSuggestions();
            performSearch();
        }

        // 更新高亮
        function updateHighlight() {
            const items = document.querySelectorAll('.suggestion-item');
            items.forEach((item, index) => {
                if (index === selectedIndex) {
                    item.classList.add('highlighted');
                } else {
                    item.classList.remove('highlighted');
                }
            });
        }

        // HTML转义
        function escapeHtml(text) {
            const div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        }

        // 处理输入事件
        const debouncedFetch = debounce(fetchSuggestions, 300);
        function handleSearchInput(event) {
            const query = event.target.value;
            debouncedFetch(query);
        }

        // 键盘导航
        document.addEventListener('keydown', (e) => {
            const list = document.getElementById('suggestionsList');
            if (list.style.display === 'none' || currentSuggestions.length === 0) {
                return;
            }

            if (e.key === 'ArrowDown') {
                e.preventDefault();
                selectedIndex = (selectedIndex + 1) % currentSuggestions.length;
                updateHighlight();
            } else if (e.key === 'ArrowUp') {
                e.preventDefault();
                selectedIndex = selectedIndex <= 0 ? currentSuggestions.length - 1 : selectedIndex - 1;
                updateHighlight();
            } else if (e.key === 'Enter' && selectedIndex >= 0) {
                e.preventDefault();
                selectSuggestion(currentSuggestions[selectedIndex].canon);
            } else if (e.key === 'Escape') {
                hideSuggestions();
            }
        });

        // 点击外部关闭建议列表
        document.addEventListener('click', (e) => {
            const list = document.getElementById('suggestionsList');
            const input = document.getElementById('searchInput');
            if (!list.contains(e.target) && e.target !== input) {
                hideSuggestions();
            }
        });
    </script>
</body>
</html>