- 新增菜品对比功能,支持1v1左右和1vN上下布局切换 - 新增食物相生相克查询工具,包含API服务和详情页面 - 优化平台工具类,移除冗余的鸿蒙系统检测逻辑 - 更新版本号至1.5.1,修改更新日志和版本说明 - 修复多个页面列表分隔符构建器参数警告 - 新增雷达图组件,用于展示多维度对比数据 - 新增可编辑数值组件,支持双击编辑和范围验证 - 优化导出按钮,增加对比功能入口 - 新增搜索引擎枚举工具类 - 更新应用路由配置,添加对比和相生相克相关页面
1445 lines
38 KiB
HTML
1445 lines
38 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>食物相生相克 - 预览</title>
|
||
<style>
|
||
:root {
|
||
--primary: #007AFF;
|
||
--primary-light: rgba(0,122,255,0.12);
|
||
--secondary: #FF9500;
|
||
--background: #F2F2F7;
|
||
--card: #FFFFFF;
|
||
--text1: #1C1C1E;
|
||
--text2: #8E8E93;
|
||
--text3: #C7C7CC;
|
||
--green: #34C759;
|
||
--red: #FF3B30;
|
||
--orange: #FF9500;
|
||
--radius-sm: 8px;
|
||
--radius-md: 12px;
|
||
--radius-lg: 20px;
|
||
--radius-xl: 28px;
|
||
--space-1: 4px;
|
||
--space-2: 8px;
|
||
--space-3: 12px;
|
||
--space-4: 16px;
|
||
--space-5: 20px;
|
||
--space-6: 24px;
|
||
--space-7: 32px;
|
||
--shadow-sm: 0 1px 3px rgba(0,0,0,0.06);
|
||
--shadow-md: 0 4px 12px rgba(0,0,0,0.08);
|
||
--shadow-lg: 0 8px 24px rgba(0,0,0,0.1);
|
||
--font-xs: 11px;
|
||
--font-sm: 12px;
|
||
--font-md: 14px;
|
||
--font-lg: 16px;
|
||
--font-xl: 18px;
|
||
--font-xxl: 22px;
|
||
--glass-bg: rgba(255,255,255,0.72);
|
||
--glass-blur: 20px;
|
||
--glass-border: rgba(255,255,255,0.5);
|
||
}
|
||
|
||
* { margin:0; padding:0; box-sizing:border-box; }
|
||
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'Helvetica Neue', sans-serif;
|
||
background: var(--background);
|
||
color: var(--text1);
|
||
min-height: 100vh;
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
.app-container {
|
||
max-width: 480px;
|
||
margin: 0 auto;
|
||
min-height: 100vh;
|
||
background: var(--background);
|
||
position: relative;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
/* Header */
|
||
.header {
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 100;
|
||
background: rgba(242,242,247,0.72);
|
||
backdrop-filter: blur(var(--glass-blur));
|
||
-webkit-backdrop-filter: blur(var(--glass-blur));
|
||
border-bottom: 0.5px solid rgba(0,0,0,0.06);
|
||
padding: var(--space-3) var(--space-4) var(--space-3);
|
||
}
|
||
|
||
.header-top {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-3);
|
||
margin-bottom: var(--space-3);
|
||
}
|
||
|
||
.header-icon {
|
||
width: 44px;
|
||
height: 44px;
|
||
border-radius: var(--radius-md);
|
||
background: linear-gradient(135deg, #34C759, #30D158);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 22px;
|
||
box-shadow: 0 4px 12px rgba(52,199,89,0.3);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.header-info { flex:1; min-width:0; }
|
||
|
||
.header-title {
|
||
font-size: var(--font-xxl);
|
||
font-weight: 700;
|
||
letter-spacing: -0.5px;
|
||
}
|
||
|
||
.header-subtitle {
|
||
font-size: var(--font-sm);
|
||
color: var(--text2);
|
||
margin-top: 2px;
|
||
}
|
||
|
||
.header-badge {
|
||
padding: var(--space-1) var(--space-2);
|
||
background: var(--primary-light);
|
||
border-radius: var(--radius-sm);
|
||
font-size: var(--font-xs);
|
||
font-weight: 600;
|
||
color: var(--primary);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* Search Bar */
|
||
.search-bar {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 40px;
|
||
background: rgba(0,0,0,0.04);
|
||
border-radius: var(--radius-md);
|
||
padding: 0 var(--space-3);
|
||
gap: var(--space-2);
|
||
}
|
||
|
||
.search-bar svg { flex-shrink:0; color: var(--text3); }
|
||
|
||
.search-bar input {
|
||
flex: 1;
|
||
border: none;
|
||
background: none;
|
||
font-size: var(--font-md);
|
||
color: var(--text1);
|
||
outline: none;
|
||
}
|
||
|
||
.search-bar input::placeholder { color: var(--text3); }
|
||
|
||
.search-clear {
|
||
width: 18px;
|
||
height: 18px;
|
||
border-radius: 50%;
|
||
background: var(--text3);
|
||
color: white;
|
||
display: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 10px;
|
||
cursor: pointer;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.search-clear.show { display: flex; }
|
||
|
||
/* Hot Tags */
|
||
.hot-tags {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: var(--space-2);
|
||
padding: var(--space-2) var(--space-4) 0;
|
||
}
|
||
|
||
.hot-tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
padding: 6px 12px;
|
||
background: var(--card);
|
||
border-radius: 16px;
|
||
font-size: var(--font-sm);
|
||
font-weight: 500;
|
||
color: var(--text2);
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
box-shadow: var(--shadow-sm);
|
||
white-space: nowrap;
|
||
border: 1px solid rgba(0,0,0,0.03);
|
||
}
|
||
|
||
.hot-tag:hover {
|
||
background: var(--primary-light);
|
||
color: var(--primary);
|
||
transform: scale(1.04);
|
||
}
|
||
|
||
.hot-tag:active {
|
||
transform: scale(0.96);
|
||
}
|
||
|
||
.hot-tag-emoji { font-size: 14px; }
|
||
|
||
.hot-tag.active {
|
||
background: linear-gradient(135deg, #007AFF, #5856D6);
|
||
color: white;
|
||
box-shadow: 0 3px 10px rgba(0,122,255,0.3);
|
||
}
|
||
|
||
/* Category Tabs */
|
||
.category-tabs {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
padding: var(--space-3) var(--space-4);
|
||
overflow-x: auto;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
.category-tabs::-webkit-scrollbar { display: none; }
|
||
|
||
.category-tab {
|
||
padding: var(--space-2) var(--space-4);
|
||
border-radius: 20px;
|
||
font-size: var(--font-md);
|
||
font-weight: 500;
|
||
white-space: nowrap;
|
||
cursor: pointer;
|
||
transition: all 0.25s ease;
|
||
border: 1.5px solid transparent;
|
||
background: var(--card);
|
||
color: var(--text2);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
.category-tab:hover { transform: scale(1.03); }
|
||
|
||
.category-tab.active {
|
||
background: linear-gradient(135deg, #34C759, #30D158);
|
||
color: white;
|
||
box-shadow: 0 4px 12px rgba(52,199,89,0.3);
|
||
}
|
||
|
||
.category-tab.active-xiangke {
|
||
background: linear-gradient(135deg, #FF3B30, #FF6B6B);
|
||
box-shadow: 0 4px 12px rgba(255,59,48,0.3);
|
||
}
|
||
|
||
.category-tab .tab-icon { margin-right: 4px; }
|
||
|
||
/* Hot Section */
|
||
.section {
|
||
padding: var(--space-2) var(--space-4);
|
||
}
|
||
|
||
.section-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: var(--space-3);
|
||
}
|
||
|
||
.section-title {
|
||
font-size: var(--font-lg);
|
||
font-weight: 700;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-2);
|
||
}
|
||
|
||
.section-action {
|
||
font-size: var(--font-sm);
|
||
color: var(--primary);
|
||
cursor: pointer;
|
||
}
|
||
|
||
/* Hot Cards Horizontal Scroll */
|
||
.hot-scroll {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
overflow-x: auto;
|
||
padding-bottom: var(--space-2);
|
||
-webkit-overflow-scrolling: touch;
|
||
scroll-snap-type: x mandatory;
|
||
}
|
||
|
||
.hot-scroll::-webkit-scrollbar { display: none; }
|
||
|
||
.hot-card {
|
||
min-width: 160px;
|
||
max-width: 160px;
|
||
background: var(--card);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--space-4);
|
||
box-shadow: var(--shadow-md);
|
||
scroll-snap-align: start;
|
||
cursor: pointer;
|
||
transition: transform 0.2s ease;
|
||
}
|
||
|
||
.hot-card:hover { transform: translateY(-2px); }
|
||
|
||
.hot-card-icon {
|
||
width: 48px;
|
||
height: 48px;
|
||
border-radius: var(--radius-md);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 24px;
|
||
margin-bottom: var(--space-3);
|
||
}
|
||
|
||
.hot-card-icon.xiangsheng {
|
||
background: linear-gradient(135deg, rgba(52,199,89,0.15), rgba(48,209,88,0.08));
|
||
}
|
||
|
||
.hot-card-icon.xiangke {
|
||
background: linear-gradient(135deg, rgba(255,59,48,0.15), rgba(255,107,107,0.08));
|
||
}
|
||
|
||
.hot-card-name {
|
||
font-size: var(--font-md);
|
||
font-weight: 600;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.hot-card-desc {
|
||
font-size: var(--font-xs);
|
||
color: var(--text2);
|
||
line-height: 1.4;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.hot-card-views {
|
||
margin-top: var(--space-2);
|
||
font-size: var(--font-xs);
|
||
color: var(--text3);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
|
||
/* Food List */
|
||
.food-list {
|
||
padding: 0 var(--space-4);
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-3);
|
||
padding-bottom: 100px;
|
||
}
|
||
|
||
.food-card {
|
||
background: var(--card);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--space-4);
|
||
box-shadow: var(--shadow-sm);
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.food-card:hover { box-shadow: var(--shadow-md); }
|
||
|
||
.food-card::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
bottom: 0;
|
||
width: 4px;
|
||
border-radius: 0 4px 4px 0;
|
||
}
|
||
|
||
.food-card.xiangsheng::before {
|
||
background: linear-gradient(180deg, #34C759, #30D158);
|
||
}
|
||
|
||
.food-card.xiangke::before {
|
||
background: linear-gradient(180deg, #FF3B30, #FF6B6B);
|
||
}
|
||
|
||
.food-card-top {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: var(--space-3);
|
||
}
|
||
|
||
.food-card-emoji {
|
||
width: 52px;
|
||
height: 52px;
|
||
border-radius: var(--radius-md);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 28px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.food-card-emoji.xiangsheng {
|
||
background: linear-gradient(135deg, rgba(52,199,89,0.15), rgba(48,209,88,0.08));
|
||
}
|
||
|
||
.food-card-emoji.xiangke {
|
||
background: linear-gradient(135deg, rgba(255,59,48,0.15), rgba(255,107,107,0.08));
|
||
}
|
||
|
||
.food-card-content { flex:1; min-width:0; }
|
||
|
||
.food-card-name {
|
||
font-size: var(--font-lg);
|
||
font-weight: 600;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.food-card-tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
padding: 2px 8px;
|
||
border-radius: 10px;
|
||
font-size: var(--font-xs);
|
||
font-weight: 600;
|
||
margin-bottom: var(--space-2);
|
||
}
|
||
|
||
.food-card-tag.xiangsheng {
|
||
background: rgba(52,199,89,0.12);
|
||
color: #34C759;
|
||
}
|
||
|
||
.food-card-tag.xiangke {
|
||
background: rgba(255,59,48,0.12);
|
||
color: #FF3B30;
|
||
}
|
||
|
||
.food-card-desc {
|
||
font-size: var(--font-sm);
|
||
color: var(--text2);
|
||
line-height: 1.5;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.food-card-bottom {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-top: var(--space-3);
|
||
padding-top: var(--space-3);
|
||
border-top: 0.5px solid rgba(0,0,0,0.04);
|
||
}
|
||
|
||
.food-card-views {
|
||
font-size: var(--font-xs);
|
||
color: var(--text3);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
|
||
.food-card-arrow {
|
||
width: 28px;
|
||
height: 28px;
|
||
border-radius: 50%;
|
||
background: var(--primary-light);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: var(--primary);
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* Detail Modal */
|
||
.modal-overlay {
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(0,0,0,0.4);
|
||
backdrop-filter: blur(8px);
|
||
-webkit-backdrop-filter: blur(8px);
|
||
z-index: 200;
|
||
display: none;
|
||
align-items: flex-end;
|
||
justify-content: center;
|
||
}
|
||
|
||
.modal-overlay.show { display: flex; }
|
||
|
||
.modal-sheet {
|
||
width: 100%;
|
||
max-width: 480px;
|
||
max-height: 85vh;
|
||
background: var(--card);
|
||
border-radius: var(--radius-xl) var(--radius-xl) 0 0;
|
||
overflow: hidden;
|
||
animation: slideUp 0.35s cubic-bezier(0.32,0.72,0,1);
|
||
}
|
||
|
||
@keyframes slideUp {
|
||
from { transform: translateY(100%); }
|
||
to { transform: translateY(0); }
|
||
}
|
||
|
||
.modal-handle {
|
||
width: 36px;
|
||
height: 5px;
|
||
background: var(--text3);
|
||
border-radius: 3px;
|
||
margin: var(--space-2) auto;
|
||
}
|
||
|
||
.modal-content {
|
||
padding: var(--space-2) var(--space-5) var(--space-7);
|
||
overflow-y: auto;
|
||
max-height: calc(85vh - 30px);
|
||
}
|
||
|
||
.modal-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-4);
|
||
margin-bottom: var(--space-5);
|
||
}
|
||
|
||
.modal-icon {
|
||
width: 64px;
|
||
height: 64px;
|
||
border-radius: var(--radius-lg);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 32px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.modal-icon.xiangsheng {
|
||
background: linear-gradient(135deg, rgba(52,199,89,0.2), rgba(48,209,88,0.1));
|
||
}
|
||
|
||
.modal-icon.xiangke {
|
||
background: linear-gradient(135deg, rgba(255,59,48,0.2), rgba(255,107,107,0.1));
|
||
}
|
||
|
||
.modal-title {
|
||
font-size: var(--font-xxl);
|
||
font-weight: 700;
|
||
}
|
||
|
||
.modal-tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
padding: 4px 10px;
|
||
border-radius: 12px;
|
||
font-size: var(--font-sm);
|
||
font-weight: 600;
|
||
margin-top: 4px;
|
||
}
|
||
|
||
.modal-tag.xiangsheng { background: rgba(52,199,89,0.12); color: #34C759; }
|
||
.modal-tag.xiangke { background: rgba(255,59,48,0.12); color: #FF3B30; }
|
||
|
||
.modal-section-title {
|
||
font-size: var(--font-md);
|
||
font-weight: 600;
|
||
color: var(--text2);
|
||
margin-bottom: var(--space-3);
|
||
margin-top: var(--space-5);
|
||
}
|
||
|
||
.modal-desc {
|
||
font-size: var(--font-md);
|
||
line-height: 1.7;
|
||
color: var(--text1);
|
||
padding: var(--space-4);
|
||
background: var(--background);
|
||
border-radius: var(--radius-md);
|
||
}
|
||
|
||
.modal-related {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-2);
|
||
}
|
||
|
||
.modal-related-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-3);
|
||
padding: var(--space-3);
|
||
background: var(--background);
|
||
border-radius: var(--radius-md);
|
||
cursor: pointer;
|
||
transition: background 0.2s;
|
||
}
|
||
|
||
.modal-related-item:hover { background: rgba(0,0,0,0.04); }
|
||
|
||
.modal-related-icon {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: var(--radius-sm);
|
||
background: var(--primary-light);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.modal-related-name { font-size: var(--font-md); font-weight: 500; }
|
||
.modal-related-arrow { margin-left: auto; color: var(--text3); font-size: 14px; }
|
||
|
||
.modal-nav {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
margin-top: var(--space-5);
|
||
}
|
||
|
||
.modal-nav-btn {
|
||
flex: 1;
|
||
padding: var(--space-3);
|
||
border-radius: var(--radius-md);
|
||
border: 1.5px solid rgba(0,0,0,0.06);
|
||
background: var(--card);
|
||
font-size: var(--font-md);
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: var(--space-2);
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.modal-nav-btn:hover { background: var(--background); }
|
||
|
||
.modal-actions {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
margin-top: var(--space-4);
|
||
}
|
||
|
||
.modal-action-btn {
|
||
flex: 1;
|
||
padding: var(--space-3) var(--space-4);
|
||
border-radius: var(--radius-md);
|
||
border: none;
|
||
font-size: var(--font-md);
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: var(--space-2);
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.modal-action-btn.copy {
|
||
background: var(--background);
|
||
color: var(--text1);
|
||
border: 1.5px solid rgba(0,0,0,0.06);
|
||
}
|
||
|
||
.modal-action-btn.copy:hover { background: rgba(0,0,0,0.06); }
|
||
|
||
.modal-action-btn.search {
|
||
background: linear-gradient(135deg, #007AFF, #5856D6);
|
||
color: white;
|
||
box-shadow: 0 4px 12px rgba(0,122,255,0.3);
|
||
}
|
||
|
||
.modal-action-btn.search:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(0,122,255,0.4); }
|
||
|
||
.modal-action-btn.copied {
|
||
background: rgba(52,199,89,0.12);
|
||
color: #34C759;
|
||
border-color: rgba(52,199,89,0.2);
|
||
}
|
||
|
||
.search-engine-menu {
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(0,0,0,0.4);
|
||
backdrop-filter: blur(8px);
|
||
-webkit-backdrop-filter: blur(8px);
|
||
z-index: 300;
|
||
display: none;
|
||
align-items: flex-end;
|
||
justify-content: center;
|
||
}
|
||
|
||
.search-engine-menu.show { display: flex; }
|
||
|
||
.search-engine-sheet {
|
||
width: 100%;
|
||
max-width: 480px;
|
||
background: var(--card);
|
||
border-radius: var(--radius-xl) var(--radius-xl) 0 0;
|
||
padding: var(--space-2) 0 var(--space-7);
|
||
animation: slideUp 0.3s cubic-bezier(0.32,0.72,0,1);
|
||
}
|
||
|
||
.search-engine-handle {
|
||
width: 36px;
|
||
height: 5px;
|
||
background: var(--text3);
|
||
border-radius: 3px;
|
||
margin: var(--space-2) auto var(--space-3);
|
||
}
|
||
|
||
.search-engine-title {
|
||
font-size: var(--font-lg);
|
||
font-weight: 600;
|
||
text-align: center;
|
||
margin-bottom: var(--space-4);
|
||
padding: 0 var(--space-4);
|
||
}
|
||
|
||
.search-engine-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: var(--space-3);
|
||
padding: 0 var(--space-4);
|
||
}
|
||
|
||
.search-engine-card {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-3);
|
||
padding: var(--space-4);
|
||
background: var(--background);
|
||
border-radius: var(--radius-md);
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
border: 1.5px solid transparent;
|
||
}
|
||
|
||
.search-engine-card:hover { border-color: var(--primary); transform: scale(1.02); }
|
||
|
||
.search-engine-card-icon {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: var(--radius-sm);
|
||
background: var(--primary-light);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 20px;
|
||
}
|
||
|
||
.search-engine-card-name { font-size: var(--font-md); font-weight: 600; }
|
||
.search-engine-card-url { font-size: var(--font-xs); color: var(--text3); }
|
||
|
||
/* Loading */
|
||
.loading-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: var(--space-7);
|
||
gap: var(--space-3);
|
||
}
|
||
|
||
.loading-spinner {
|
||
width: 32px;
|
||
height: 32px;
|
||
border: 3px solid var(--text3);
|
||
border-top-color: var(--primary);
|
||
border-radius: 50%;
|
||
animation: spin 0.8s linear infinite;
|
||
}
|
||
|
||
@keyframes spin { to { transform: rotate(360deg); } }
|
||
|
||
.loading-text { font-size: var(--font-sm); color: var(--text2); }
|
||
|
||
/* Empty State */
|
||
.empty-state {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: var(--space-7);
|
||
gap: var(--space-3);
|
||
}
|
||
|
||
.empty-icon {
|
||
width: 80px;
|
||
height: 80px;
|
||
border-radius: var(--radius-xl);
|
||
background: var(--primary-light);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 36px;
|
||
}
|
||
|
||
.empty-title { font-size: var(--font-lg); font-weight: 600; }
|
||
.empty-desc { font-size: var(--font-sm); color: var(--text2); }
|
||
|
||
/* Random Button */
|
||
.random-fab {
|
||
position: fixed;
|
||
bottom: var(--space-6);
|
||
right: calc(50% - 240px + var(--space-5));
|
||
width: 56px;
|
||
height: 56px;
|
||
border-radius: 50%;
|
||
background: linear-gradient(135deg, #FF9500, #FF6B35);
|
||
color: white;
|
||
border: none;
|
||
font-size: 24px;
|
||
cursor: pointer;
|
||
box-shadow: 0 6px 20px rgba(255,149,0,0.4);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: transform 0.2s;
|
||
z-index: 50;
|
||
}
|
||
|
||
.random-fab:hover { transform: scale(1.1); }
|
||
|
||
@media (max-width: 480px) {
|
||
.random-fab { right: var(--space-5); }
|
||
}
|
||
|
||
/* Stats Bar */
|
||
.stats-bar {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
padding: var(--space-2) var(--space-4);
|
||
overflow-x: auto;
|
||
}
|
||
|
||
.stats-bar::-webkit-scrollbar { display: none; }
|
||
|
||
.stat-chip {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: var(--space-2) var(--space-3);
|
||
background: var(--card);
|
||
border-radius: var(--radius-md);
|
||
box-shadow: var(--shadow-sm);
|
||
white-space: nowrap;
|
||
font-size: var(--font-sm);
|
||
}
|
||
|
||
.stat-chip-value { font-weight: 700; color: var(--primary); }
|
||
.stat-chip-label { color: var(--text2); }
|
||
|
||
/* Pull to refresh indicator */
|
||
.refresh-indicator {
|
||
text-align: center;
|
||
padding: var(--space-3);
|
||
font-size: var(--font-sm);
|
||
color: var(--text2);
|
||
display: none;
|
||
}
|
||
|
||
.refresh-indicator.show { display: block; }
|
||
|
||
/* Pagination */
|
||
.load-more {
|
||
text-align: center;
|
||
padding: var(--space-4);
|
||
}
|
||
|
||
.load-more-btn {
|
||
padding: var(--space-3) var(--space-6);
|
||
background: var(--card);
|
||
border: 1.5px solid rgba(0,0,0,0.06);
|
||
border-radius: 20px;
|
||
font-size: var(--font-md);
|
||
font-weight: 500;
|
||
color: var(--primary);
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.load-more-btn:hover { background: var(--primary-light); }
|
||
|
||
/* Dark mode support */
|
||
@media (prefers-color-scheme: dark) {
|
||
:root {
|
||
--background: #000000;
|
||
--card: #1C1C1E;
|
||
--text1: #FFFFFF;
|
||
--text2: #EBEBF5;
|
||
--text3: #8E8E93;
|
||
--primary-light: rgba(10,132,255,0.18);
|
||
--glass-bg: rgba(28,28,30,0.72);
|
||
--shadow-sm: 0 1px 3px rgba(0,0,0,0.2);
|
||
--shadow-md: 0 4px 12px rgba(0,0,0,0.3);
|
||
}
|
||
.header { background: rgba(0,0,0,0.72); border-bottom-color: rgba(255,255,255,0.06); }
|
||
.search-bar { background: rgba(255,255,255,0.06); }
|
||
.modal-sheet { background: #1C1C1E; }
|
||
.modal-desc { background: #2C2C2E; }
|
||
.modal-related-item { background: #2C2C2E; }
|
||
.modal-related-item:hover { background: #3A3A3C; }
|
||
.food-card { box-shadow: var(--shadow-sm); }
|
||
.food-card-bottom { border-top-color: rgba(255,255,255,0.06); }
|
||
.hot-tag { background: #2C2C2E; color: var(--text2); border-color: rgba(255,255,255,0.06); }
|
||
.hot-tag:hover { background: var(--primary-light); }
|
||
.search-engine-sheet { background: #1C1C1E; }
|
||
.search-engine-card { background: #2C2C2E; }
|
||
.modal-action-btn.copy { background: #2C2C2E; border-color: rgba(255,255,255,0.06); color: var(--text1); }
|
||
.modal-action-btn.copy:hover { background: #3A3A3C; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="app-container" id="app">
|
||
<!-- Header -->
|
||
<div class="header">
|
||
<div class="header-top">
|
||
<div class="header-icon">🥗</div>
|
||
<div class="header-info">
|
||
<div class="header-title">食物相生相克</div>
|
||
<div class="header-subtitle">了解食物搭配的宜忌</div>
|
||
</div>
|
||
<div class="header-badge" id="totalCount">加载中...</div>
|
||
</div>
|
||
<div class="search-bar">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
|
||
<input type="text" id="searchInput" placeholder="搜索食物名称..." />
|
||
<div class="search-clear" id="searchClear" onclick="clearSearch()">✕</div>
|
||
</div>
|
||
<div class="hot-tags" id="hotTags">
|
||
<div class="hot-tag" onclick="quickSearch('苹果')"><span class="hot-tag-emoji">🍎</span>苹果</div>
|
||
<div class="hot-tag" onclick="quickSearch('牛奶')"><span class="hot-tag-emoji">🥛</span>牛奶</div>
|
||
<div class="hot-tag" onclick="quickSearch('鸡蛋')"><span class="hot-tag-emoji">🥚</span>鸡蛋</div>
|
||
<div class="hot-tag" onclick="quickSearch('蜂蜜')"><span class="hot-tag-emoji">🍯</span>蜂蜜</div>
|
||
<div class="hot-tag" onclick="quickSearch('香蕉')"><span class="hot-tag-emoji">🍌</span>香蕉</div>
|
||
<div class="hot-tag" onclick="quickSearch('虾')"><span class="hot-tag-emoji">🦐</span>虾</div>
|
||
<div class="hot-tag" onclick="quickSearch('豆腐')"><span class="hot-tag-emoji">🧈</span>豆腐</div>
|
||
<div class="hot-tag" onclick="quickSearch('菠菜')"><span class="hot-tag-emoji">🥬</span>菠菜</div>
|
||
<div class="hot-tag" onclick="quickSearch('土豆')"><span class="hot-tag-emoji">🥔</span>土豆</div>
|
||
<div class="hot-tag" onclick="quickSearch('螃蟹')"><span class="hot-tag-emoji">🦀</span>螃蟹</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Category Tabs -->
|
||
<div class="category-tabs" id="categoryTabs">
|
||
<div class="category-tab active" data-category="all" onclick="selectCategory(this, 'all')">
|
||
<span class="tab-icon">📋</span>全部
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Stats Bar -->
|
||
<div class="stats-bar" id="statsBar">
|
||
<div class="stat-chip">
|
||
<span class="stat-chip-value" id="statTotal">-</span>
|
||
<span class="stat-chip-label">条记录</span>
|
||
</div>
|
||
<div class="stat-chip">
|
||
<span class="stat-chip-value" id="statSheng">-</span>
|
||
<span class="stat-chip-label">🟢 相生</span>
|
||
</div>
|
||
<div class="stat-chip">
|
||
<span class="stat-chip-value" id="statKe">-</span>
|
||
<span class="stat-chip-label">🔴 相克</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Hot Section -->
|
||
<div class="section" id="hotSection" style="display:none">
|
||
<div class="section-header">
|
||
<div class="section-title">🔥 热门食物</div>
|
||
<div class="section-action" onclick="loadHot()">换一批</div>
|
||
</div>
|
||
<div class="hot-scroll" id="hotList"></div>
|
||
</div>
|
||
|
||
<!-- Food List -->
|
||
<div class="food-list" id="foodList">
|
||
<div class="loading-container">
|
||
<div class="loading-spinner"></div>
|
||
<div class="loading-text">加载中...</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Load More -->
|
||
<div class="load-more" id="loadMore" style="display:none">
|
||
<button class="load-more-btn" onclick="loadMore()">加载更多</button>
|
||
</div>
|
||
|
||
<!-- Random FAB -->
|
||
<button class="random-fab" onclick="loadRandom()" title="随机推荐">🎲</button>
|
||
</div>
|
||
|
||
<!-- Detail Modal -->
|
||
<div class="modal-overlay" id="detailModal" onclick="closeModalOutside(event)">
|
||
<div class="modal-sheet">
|
||
<div class="modal-handle"></div>
|
||
<div class="modal-content" id="modalContent"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Search Engine Menu -->
|
||
<div class="search-engine-menu" id="searchEngineMenu" onclick="closeSearchEngineOutside(event)">
|
||
<div class="search-engine-sheet">
|
||
<div class="search-engine-handle"></div>
|
||
<div class="search-engine-title">🔍 选择搜索引擎</div>
|
||
<div class="search-engine-grid">
|
||
<div class="search-engine-card" onclick="launchSearch('baidu')">
|
||
<div class="search-engine-card-icon">🔍</div>
|
||
<div>
|
||
<div class="search-engine-card-name">百度</div>
|
||
<div class="search-engine-card-url">baidu.com</div>
|
||
</div>
|
||
</div>
|
||
<div class="search-engine-card" onclick="launchSearch('bing')">
|
||
<div class="search-engine-card-icon">🟦</div>
|
||
<div>
|
||
<div class="search-engine-card-name">Bing</div>
|
||
<div class="search-engine-card-url">bing.com</div>
|
||
</div>
|
||
</div>
|
||
<div class="search-engine-card" onclick="launchSearch('google')">
|
||
<div class="search-engine-card-icon">🌐</div>
|
||
<div>
|
||
<div class="search-engine-card-name">谷歌</div>
|
||
<div class="search-engine-card-url">google.com</div>
|
||
</div>
|
||
</div>
|
||
<div class="search-engine-card" onclick="launchSearch('sogou')">
|
||
<div class="search-engine-card-icon">🐕</div>
|
||
<div>
|
||
<div class="search-engine-card-name">搜狗</div>
|
||
<div class="search-engine-card-url">sogou.com</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
const API_BASE = 'https://tools.wktyl.com/api/shiwu';
|
||
let currentPage = 1;
|
||
let currentCategoryId = null;
|
||
let isLoading = false;
|
||
let hasMore = true;
|
||
let categories = [];
|
||
let searchTimer = null;
|
||
|
||
const foodEmojis = {
|
||
'苹果': '🍎', '香蕉': '🍌', '葡萄': '🍇', '草莓': '🍓', '西瓜': '🍉',
|
||
'橙子': '🍊', '柠檬': '🍋', '桃子': '🍑', '梨': '🍐', '芒果': '🥭',
|
||
'菠萝': '🍍', '樱桃': '🍒', '石榴': '🫐', '柿子': '🟠', '荔枝': '🔴',
|
||
'牛奶': '🥛', '鸡蛋': '🥚', '蜂蜜': '🍯', '豆腐': '🧈', '萝卜': '🥕',
|
||
'菠菜': '🥬', '番茄': '🍅', '土豆': '🥔', '黄瓜': '🥒', '茄子': '🍆',
|
||
'辣椒': '🌶️', '大蒜': '🧄', '洋葱': '🧅', '蘑菇': '🍄', '芹菜': '🥦',
|
||
'白菜': '🥬', '花生': '🥜', '核桃': '🌰', '红枣': '🫐', '枸杞': '🔴',
|
||
'绿茶': '🍵', '咖啡': '☕', '啤酒': '🍺', '白酒': '🍶', '红酒': '🍷',
|
||
'虾': '🦐', '蟹': '🦀', '鱼': '🐟', '鸡肉': '🍗', '牛肉': '🥩',
|
||
'猪肉': '🥓', '羊肉': '🍖', '鸭肉': '🦆', '狗肉': '🐕', '兔肉': '🐇',
|
||
'豆浆': '🥛', '酸奶': '🥛', '奶酪': '🧀', '巧克力': '🍫', '冰淇淋': '🍦',
|
||
'醋': '🫗', '酱油': '🫗', '生姜': '🫚', '葱': '🧅', '香菜': '🌿',
|
||
'红薯': '🍠', '山药': '🥔', '莲藕': '🪷', '冬瓜': '🟢', '南瓜': '🎃',
|
||
'丝瓜': '🥒', '苦瓜': '🥒', '木耳': '🍄', '银耳': '🍄', '海带': '🌊',
|
||
'紫菜': '🌊', '芝麻': '🫘', '栗子': '🌰', '桂圆': '🔴', '山楂': '🔴',
|
||
'木瓜': '🟡', '榴莲': '🟡', '椰子': '🥥', '甘蔗': '🎋', '杨梅': '🔴',
|
||
'枇杷': '🟡', '杨桃': '⭐', '猕猴桃': '🥝', '火龙果': '🐉', '百香果': '🟣',
|
||
};
|
||
|
||
function getEmoji(name) {
|
||
for (const [key, val] of Object.entries(foodEmojis)) {
|
||
if (name.includes(key)) return val;
|
||
}
|
||
return '🍽️';
|
||
}
|
||
|
||
function getCategoryClass(categoryName) {
|
||
return categoryName === '相生' ? 'xiangsheng' : 'xiangke';
|
||
}
|
||
|
||
function getCategoryIcon(categoryName) {
|
||
return categoryName === '相生' ? '✅' : '⚠️';
|
||
}
|
||
|
||
async function fetchAPI(endpoint, params = {}) {
|
||
const url = new URL(`${API_BASE}/${endpoint}`);
|
||
Object.entries(params).forEach(([k, v]) => {
|
||
if (v !== null && v !== undefined && v !== '') url.searchParams.set(k, v);
|
||
});
|
||
try {
|
||
const resp = await fetch(url.toString());
|
||
const data = await resp.json();
|
||
if (data.code === 1) return data.data;
|
||
return null;
|
||
} catch (e) {
|
||
console.error('API Error:', e);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
async function loadCategories() {
|
||
const data = await fetchAPI('category');
|
||
if (!data) return;
|
||
categories = data.list || [];
|
||
const tabsEl = document.getElementById('categoryTabs');
|
||
categories.forEach(cat => {
|
||
const tab = document.createElement('div');
|
||
tab.className = 'category-tab';
|
||
tab.dataset.category = cat.id;
|
||
const icon = cat.name === '相生' ? '✅' : '⚠️';
|
||
tab.innerHTML = `<span class="tab-icon">${icon}</span>${cat.name}`;
|
||
tab.onclick = function() { selectCategory(this, cat.id); };
|
||
tabsEl.appendChild(tab);
|
||
});
|
||
const statSheng = categories.find(c => c.name === '相生');
|
||
const statKe = categories.find(c => c.name === '相克');
|
||
if (statSheng) document.getElementById('statSheng').textContent = statSheng.count || '-';
|
||
if (statKe) document.getElementById('statKe').textContent = statKe.count || '-';
|
||
}
|
||
|
||
async function loadFoodList(reset = false) {
|
||
if (isLoading) return;
|
||
if (reset) {
|
||
currentPage = 1;
|
||
hasMore = true;
|
||
document.getElementById('foodList').innerHTML = '';
|
||
}
|
||
if (!hasMore) return;
|
||
|
||
isLoading = true;
|
||
const params = { page: currentPage, limit: 20 };
|
||
if (currentCategoryId) params.category_id = currentCategoryId;
|
||
|
||
const data = await fetchAPI('list', params);
|
||
isLoading = false;
|
||
|
||
if (!data) {
|
||
document.getElementById('foodList').innerHTML = `
|
||
<div class="empty-state">
|
||
<div class="empty-icon">😔</div>
|
||
<div class="empty-title">加载失败</div>
|
||
<div class="empty-desc">请检查网络后重试</div>
|
||
</div>`;
|
||
return;
|
||
}
|
||
|
||
document.getElementById('statTotal').textContent = data.total || '-';
|
||
document.getElementById('totalCount').textContent = `${data.total || 0} 条`;
|
||
|
||
const list = data.list || [];
|
||
if (list.length === 0 && currentPage === 1) {
|
||
document.getElementById('foodList').innerHTML = `
|
||
<div class="empty-state">
|
||
<div class="empty-icon">🔍</div>
|
||
<div class="empty-title">暂无数据</div>
|
||
<div class="empty-desc">试试其他分类或搜索</div>
|
||
</div>`;
|
||
return;
|
||
}
|
||
|
||
hasMore = currentPage < (data.last_page || 1);
|
||
const container = document.getElementById('foodList');
|
||
list.forEach(item => container.appendChild(createFoodCard(item)));
|
||
document.getElementById('loadMore').style.display = hasMore ? 'block' : 'none';
|
||
}
|
||
|
||
async function loadHot() {
|
||
const data = await fetchAPI('hot', { limit: 10 });
|
||
if (!data) return;
|
||
const section = document.getElementById('hotSection');
|
||
const list = document.getElementById('hotList');
|
||
section.style.display = 'block';
|
||
list.innerHTML = '';
|
||
(data.list || []).forEach(item => {
|
||
const catClass = getCategoryClass(item.category_name);
|
||
const card = document.createElement('div');
|
||
card.className = 'hot-card';
|
||
card.onclick = () => openDetail(item.hash_id);
|
||
card.innerHTML = `
|
||
<div class="hot-card-icon ${catClass}">${getEmoji(item.sw)}</div>
|
||
<div class="hot-card-name">${item.sw}</div>
|
||
<div class="hot-card-desc">${item.yh || ''}</div>
|
||
<div class="hot-card-views">👁 ${item.views || 0}</div>`;
|
||
list.appendChild(card);
|
||
});
|
||
}
|
||
|
||
async function loadRandom() {
|
||
const data = await fetchAPI('random', { limit: 5 });
|
||
if (!data || !data.list || data.list.length === 0) return;
|
||
openDetail(data.list[0].hash_id);
|
||
}
|
||
|
||
async function searchFood(keyword) {
|
||
if (!keyword.trim()) {
|
||
loadFoodList(true);
|
||
return;
|
||
}
|
||
isLoading = true;
|
||
document.getElementById('foodList').innerHTML = `
|
||
<div class="loading-container">
|
||
<div class="loading-spinner"></div>
|
||
<div class="loading-text">搜索中...</div>
|
||
</div>`;
|
||
document.getElementById('loadMore').style.display = 'none';
|
||
|
||
const data = await fetchAPI('search', { keyword: keyword.trim(), limit: 20 });
|
||
isLoading = false;
|
||
|
||
if (!data) {
|
||
document.getElementById('foodList').innerHTML = `
|
||
<div class="empty-state">
|
||
<div class="empty-icon">😔</div>
|
||
<div class="empty-title">搜索失败</div>
|
||
</div>`;
|
||
return;
|
||
}
|
||
|
||
const list = data.list || [];
|
||
if (list.length === 0) {
|
||
document.getElementById('foodList').innerHTML = `
|
||
<div class="empty-state">
|
||
<div class="empty-icon">🔍</div>
|
||
<div class="empty-title">未找到"${keyword}"</div>
|
||
<div class="empty-desc">试试其他关键词</div>
|
||
</div>`;
|
||
return;
|
||
}
|
||
|
||
document.getElementById('foodList').innerHTML = '';
|
||
const container = document.getElementById('foodList');
|
||
list.forEach(item => container.appendChild(createFoodCard(item)));
|
||
}
|
||
|
||
async function openDetail(id) {
|
||
const modal = document.getElementById('detailModal');
|
||
const content = document.getElementById('modalContent');
|
||
content.innerHTML = `
|
||
<div class="loading-container">
|
||
<div class="loading-spinner"></div>
|
||
<div class="loading-text">加载详情...</div>
|
||
</div>`;
|
||
modal.classList.add('show');
|
||
|
||
const data = await fetchAPI('detail', { id });
|
||
if (!data) {
|
||
content.innerHTML = `
|
||
<div class="empty-state">
|
||
<div class="empty-icon">😔</div>
|
||
<div class="empty-title">加载失败</div>
|
||
</div>`;
|
||
return;
|
||
}
|
||
|
||
const catClass = getCategoryClass(data.category_name);
|
||
content.innerHTML = `
|
||
<div class="modal-header">
|
||
<div class="modal-icon ${catClass}">${getEmoji(data.sw)}</div>
|
||
<div>
|
||
<div class="modal-title">${data.sw}</div>
|
||
<div class="modal-tag ${catClass}">${getCategoryIcon(data.category_name)} ${data.category_name}</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-section-title">📝 搭配说明</div>
|
||
<div class="modal-desc">${data.yh || '暂无说明'}</div>
|
||
<div class="modal-section-title">👁 浏览量</div>
|
||
<div class="modal-desc">${data.views || 0} 次</div>
|
||
${data.related && data.related.length > 0 ? `
|
||
<div class="modal-section-title">🔗 相关推荐</div>
|
||
<div class="modal-related">
|
||
${data.related.map(r => `
|
||
<div class="modal-related-item" onclick="openDetail('${r.hash_id}')">
|
||
<div class="modal-related-icon">${getEmoji(r.sw)}</div>
|
||
<div class="modal-related-name">${r.sw}</div>
|
||
<div class="modal-related-arrow">›</div>
|
||
</div>
|
||
`).join('')}
|
||
</div>
|
||
` : ''}
|
||
<div class="modal-nav">
|
||
${data.prev ? `<button class="modal-nav-btn" onclick="openDetail('${data.prev.hash_id}')">← ${data.prev.sw}</button>` : '<div></div>'}
|
||
${data.next ? `<button class="modal-nav-btn" onclick="openDetail('${data.next.hash_id}')">${data.next.sw} →</button>` : '<div></div>'}
|
||
</div>
|
||
<div class="modal-actions">
|
||
<button class="modal-action-btn copy" id="copyBtn" onclick="copyFoodInfo('${data.sw}', \`${(data.yh || '').replace(/`/g, '\\`')}\`)">
|
||
📋 复制信息
|
||
</button>
|
||
<button class="modal-action-btn search" onclick="showSearchEngine('${data.sw}')">
|
||
🔍 去搜索
|
||
</button>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
function closeModalOutside(e) {
|
||
if (e.target === document.getElementById('detailModal')) {
|
||
document.getElementById('detailModal').classList.remove('show');
|
||
}
|
||
}
|
||
|
||
function copyFoodInfo(name, desc) {
|
||
const text = `【${name}】食物相生相克\n${desc}`;
|
||
navigator.clipboard.writeText(text).then(() => {
|
||
const btn = document.getElementById('copyBtn');
|
||
if (btn) {
|
||
btn.classList.add('copied');
|
||
btn.innerHTML = '✅ 已复制';
|
||
setTimeout(() => {
|
||
btn.classList.remove('copied');
|
||
btn.innerHTML = '📋 复制信息';
|
||
}, 2000);
|
||
}
|
||
}).catch(() => {
|
||
const textarea = document.createElement('textarea');
|
||
textarea.value = text;
|
||
document.body.appendChild(textarea);
|
||
textarea.select();
|
||
document.execCommand('copy');
|
||
document.body.removeChild(textarea);
|
||
const btn = document.getElementById('copyBtn');
|
||
if (btn) {
|
||
btn.classList.add('copied');
|
||
btn.innerHTML = '✅ 已复制';
|
||
setTimeout(() => {
|
||
btn.classList.remove('copied');
|
||
btn.innerHTML = '📋 复制信息';
|
||
}, 2000);
|
||
}
|
||
});
|
||
}
|
||
|
||
let currentSearchKeyword = '';
|
||
|
||
function showSearchEngine(keyword) {
|
||
currentSearchKeyword = keyword;
|
||
document.getElementById('searchEngineMenu').classList.add('show');
|
||
}
|
||
|
||
function closeSearchEngineOutside(e) {
|
||
if (e.target === document.getElementById('searchEngineMenu')) {
|
||
document.getElementById('searchEngineMenu').classList.remove('show');
|
||
}
|
||
}
|
||
|
||
function launchSearch(engine) {
|
||
const keyword = currentSearchKeyword;
|
||
const encoded = encodeURIComponent(keyword + ' 相生相克');
|
||
const urls = {
|
||
baidu: `https://www.baidu.com/s?wd=${encoded}`,
|
||
bing: `https://www.bing.com/search?q=${encoded}`,
|
||
google: `https://www.google.com/search?q=${encoded}`,
|
||
sogou: `https://www.sogou.com/web?query=${encoded}`,
|
||
};
|
||
const url = urls[engine] || urls.baidu;
|
||
document.getElementById('searchEngineMenu').classList.remove('show');
|
||
window.open(url, '_blank');
|
||
}
|
||
|
||
function createFoodCard(item) {
|
||
const catClass = getCategoryClass(item.category_name);
|
||
const card = document.createElement('div');
|
||
card.className = `food-card ${catClass}`;
|
||
card.onclick = () => openDetail(item.hash_id);
|
||
card.innerHTML = `
|
||
<div class="food-card-top">
|
||
<div class="food-card-emoji ${catClass}">${getEmoji(item.sw)}</div>
|
||
<div class="food-card-content">
|
||
<div class="food-card-name">${item.sw}</div>
|
||
<div class="food-card-tag ${catClass}">${getCategoryIcon(item.category_name)} ${item.category_name}</div>
|
||
<div class="food-card-desc">${item.yh || ''}</div>
|
||
</div>
|
||
</div>
|
||
<div class="food-card-bottom">
|
||
<div class="food-card-views">👁 ${item.views || 0} 次浏览</div>
|
||
<div class="food-card-arrow">›</div>
|
||
</div>`;
|
||
return card;
|
||
}
|
||
|
||
function selectCategory(el, categoryId) {
|
||
document.querySelectorAll('.category-tab').forEach(t => {
|
||
t.classList.remove('active', 'active-xiangke');
|
||
});
|
||
el.classList.add('active');
|
||
if (categoryId !== 'all') {
|
||
const cat = categories.find(c => c.id == categoryId);
|
||
if (cat && cat.name === '相克') el.classList.add('active-xiangke');
|
||
}
|
||
currentCategoryId = categoryId === 'all' ? null : categoryId;
|
||
loadFoodList(true);
|
||
}
|
||
|
||
function loadMore() {
|
||
currentPage++;
|
||
loadFoodList();
|
||
}
|
||
|
||
function clearSearch() {
|
||
document.getElementById('searchInput').value = '';
|
||
document.getElementById('searchClear').classList.remove('show');
|
||
document.querySelectorAll('.hot-tag').forEach(t => t.classList.remove('active'));
|
||
loadFoodList(true);
|
||
}
|
||
|
||
function quickSearch(keyword) {
|
||
const input = document.getElementById('searchInput');
|
||
input.value = keyword;
|
||
document.getElementById('searchClear').classList.add('show');
|
||
document.querySelectorAll('.hot-tag').forEach(t => {
|
||
t.classList.toggle('active', t.textContent.trim().replace(/^.{1,2}/, '') === keyword || t.textContent.includes(keyword));
|
||
});
|
||
searchFood(keyword);
|
||
}
|
||
|
||
document.getElementById('searchInput').addEventListener('input', function() {
|
||
const val = this.value;
|
||
document.getElementById('searchClear').classList.toggle('show', val.length > 0);
|
||
clearTimeout(searchTimer);
|
||
searchTimer = setTimeout(() => searchFood(val), 400);
|
||
});
|
||
|
||
document.addEventListener('keydown', function(e) {
|
||
if (e.key === 'Escape') {
|
||
document.getElementById('detailModal').classList.remove('show');
|
||
}
|
||
});
|
||
|
||
async function init() {
|
||
await loadCategories();
|
||
await loadFoodList(true);
|
||
await loadHot();
|
||
|
||
const urlParams = new URLSearchParams(window.location.search);
|
||
const keyword = urlParams.get('keyword');
|
||
const foodId = urlParams.get('id');
|
||
if (keyword) {
|
||
quickSearch(keyword);
|
||
} else if (foodId) {
|
||
openDetail(foodId);
|
||
}
|
||
}
|
||
|
||
init();
|
||
</script>
|
||
</body>
|
||
</html>
|