From 62e92a08bc4f8b5109c45b1bed7707258008cb6e Mon Sep 17 00:00:00 2001 From: Midas Date: Mon, 22 Jun 2026 23:54:51 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=94=B6=E8=97=8F?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E3=80=81=E6=90=9C=E7=B4=A2=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E3=80=81=E5=A4=8D=E5=88=B6=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/index.html | 243 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 226 insertions(+), 17 deletions(-) diff --git a/public/index.html b/public/index.html index 8e77cab..d284049 100644 --- a/public/index.html +++ b/public/index.html @@ -111,6 +111,19 @@ /* Content padding for tabbar */ .main-content { padding-bottom: 80px; } + + /* My Content */ + .my-content { padding-bottom: 80px; } + .fav-item, .history-item { background: var(--card); border-radius: var(--radius); padding: 12px; margin-bottom: 8px; display: flex; gap: 10px; align-items: center; box-shadow: var(--shadow); } + .fav-img { width: 48px; height: 48px; border-radius: 6px; background: #f3f4f6; display: flex; align-items: center; justify-content: center; overflow: hidden; flex-shrink: 0; } + .fav-img img { width: 100%; height: 100%; object-fit: cover; } + .fav-info { flex: 1; min-width: 0; } + .fav-title { font-size: 13px; font-weight: 600; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; } + .fav-price { font-size: 14px; color: #ef4444; font-weight: 700; } + .fav-remove { color: var(--text-light); font-size: 18px; padding: 4px 8px; cursor: pointer; } + .history-item { justify-content: space-between; } + .history-keyword { font-size: 14px; } + .history-time { font-size: 11px; color: var(--text-light); } /* Search Results Panel */ .search-panel { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: var(--bg); z-index: 100; overflow-y: auto; } @@ -193,7 +206,45 @@ - + +
🏠 @@ -265,11 +316,14 @@ return; } dealsGrid.innerHTML = deals.map(deal => ` -
-
${deal.title}
-
${PLATFORM_NAME[deal.platform] || deal.platform}${deal.title}
-
¥${deal.price}¥${deal.originalPrice}${deal.discount}
-
🎁 预估返 ¥${deal.commission || 0}
+
+
${isFavorited('deal_'+deal.id) ? '❤️' : '🤍'}
+
+
${deal.title}
+
${PLATFORM_NAME[deal.platform] || deal.platform}${deal.title}
+
¥${deal.price}¥${deal.originalPrice}${deal.discount}
+
🎁 预估返 ¥${deal.commission || 0}
+
`).join(''); } @@ -328,16 +382,19 @@ // Render Search Results function renderSearchResults(products) { searchResults.innerHTML = products.map(p => ` -
-
${p.title}
-
-
${p.title}
-
${PLATFORM_NAME[p.platform] || p.platform} ${p.shop}
-
- ¥${p.price} - -¥${p.coupon}券 +
+
${isFavorited('product_'+p.id) ? '❤️' : '🤍'}
+
+
${p.title}
+
+
${p.title}
+
${PLATFORM_NAME[p.platform] || p.platform} ${p.shop}
+
+ ¥${p.price} + -¥${p.coupon}券 +
+
🎁 返 ¥${p.commission || 0}
-
🎁 返 ¥${p.commission || 0}
`).join(''); @@ -348,19 +405,91 @@ // Stats updated from data } + // Local Storage Keys + const FAVORITES_KEY = 'zhibisheng_favorites'; + const SEARCH_HISTORY_KEY = 'zhibisheng_search_history'; + + // Load favorites from localStorage + function getFavorites() { + try { + return JSON.parse(localStorage.getItem(FAVORITES_KEY) || '[]'); + } catch { return []; } + } + + // Save to favorites + function toggleFavorite(item, type) { + let favorites = getFavorites(); + const id = type + '_' + item.id; + const index = favorites.findIndex(f => f.id === id); + if (index > -1) { + favorites.splice(index, 1); + showToast('已取消收藏'); + } else { + favorites.unshift({ ...item, id, type, addedAt: Date.now() }); + showToast('已收藏 ~'); + } + localStorage.setItem(FAVORITES_KEY, JSON.stringify(favorites)); + renderMyTab(); + } + + // Check if favorited + function isFavorited(id) { + return getFavorites().some(f => f.id === id); + } + + // Toast notification + function showToast(msg) { + const existing = document.querySelector('.toast'); + if (existing) existing.remove(); + const toast = document.createElement('div'); + toast.className = 'toast'; + toast.textContent = msg; + toast.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:rgba(0,0,0,0.75);color:white;padding:12px 24px;border-radius:8px;font-size:14px;z-index:9999;animation:fadeIn 0.3s'; + document.body.appendChild(toast); + setTimeout(() => { toast.style.opacity = '0'; setTimeout(() => toast.remove(), 300); }, 1500); + } + + // Copy text to clipboard + function copyToClipboard(text, successMsg) { + if (navigator.clipboard) { + navigator.clipboard.writeText(text).then(() => showToast(successMsg || '已复制')).catch(() => fallbackCopy(text)); + } else { + fallbackCopy(text); + } + } + + function fallbackCopy(text) { + const ta = document.createElement('textarea'); + ta.value = text; + ta.style.position = 'fixed'; ta.style.opacity = '0'; + document.body.appendChild(ta); + ta.select(); + document.execCommand('copy'); + document.body.removeChild(ta); + showToast('已复制'); + } + // Actions function openDeal(deal) { if (deal.link && deal.link !== '#') { window.open(deal.link, '_blank'); } else { - alert('复制商品链接,请在淘宝/京东App打开购买~'); + // Generate mock coupon link + const couponLink = `https://taobao.com/item?id=${deal.id}`; + copyToClipboard(couponLink, '链接已复制,打开淘宝购买'); } } + function goToCoupon(product) { if (product.link && product.link !== '#') { window.open(product.link, '_blank'); } else { - alert('复制商品链接,请在淘宝/京东App打开购买~'); + const couponText = `${product.title} +原价: ¥${product.originalPrice} +券后: ¥${product.price} +${product.shop} +【下载淘宝APP打开链接购买】`; + copyToClipboard(couponText, '已复制商品信息'); } } @@ -369,13 +498,93 @@ searchInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') doSearch(searchInput.value); }); // Tab switching + const mainContent = document.getElementById('mainContent'); + const myContent = document.getElementById('myContent'); + document.querySelectorAll('.tab').forEach(tab => { tab.addEventListener('click', () => { document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); tab.classList.add('active'); currentTab = tab.dataset.tab; + + if (currentTab === 'my') { + mainContent.style.display = 'none'; + myContent.style.display = 'block'; + renderMyTab(); + } else { + mainContent.style.display = 'block'; + myContent.style.display = 'none'; + } }); }); + + // Render My Tab + function renderMyTab() { + const favorites = getFavorites(); + document.getElementById('myFavCount').textContent = favorites.length; + + // Render favorites + if (favorites.length === 0) { + document.getElementById('favoritesList').innerHTML = '
暂无收藏
'; + } else { + document.getElementById('favoritesList').innerHTML = favorites.map(f => ` +
+
+
+
${f.title}
+
¥${f.price}
+
+
+
+ `).join(''); + } + + // Render search history + try { + const history = JSON.parse(localStorage.getItem(SEARCH_HISTORY_KEY) || '[]'); + document.getElementById('mySearchCount').textContent = history.length; + if (history.length === 0) { + document.getElementById('searchHistoryList').innerHTML = '
暂无搜索记录
'; + } else { + document.getElementById('searchHistoryList').innerHTML = history.slice(0, 10).map(h => ` +
+ 🔍 ${h.keyword} + ${formatTime(h.time)} +
+ `).join(''); + } + } catch {} + } + + function formatTime(ts) { + const d = new Date(ts); + return `${d.getMonth()+1}/${d.getDate()} ${d.getHours()}:${String(d.getMinutes()).padStart(2, '0')}`; + } + + function searchFromHistory(keyword) { + searchInput.value = keyword; + document.querySelector('[data-tab="home"]').click(); + doSearch(keyword); + } + + function clearSearchHistory() { + localStorage.removeItem(SEARCH_HISTORY_KEY); + renderMyTab(); + showToast('已清空'); + } + + // Save search to history + const originalDoSearch = doSearch; + async function doSearch(keyword) { + if (!keyword.trim()) return; + try { + const history = JSON.parse(localStorage.getItem(SEARCH_HISTORY_KEY) || '[]'); + const filtered = history.filter(h => h.keyword !== keyword); + filtered.unshift({ keyword, time: Date.now() }); + localStorage.setItem(SEARCH_HISTORY_KEY, JSON.stringify(filtered.slice(0, 20))); + } catch {} + return originalDoSearch(keyword); + } // Start init();