本次提交完成多项核心更新: 1. 新增闲情逸致功能模块,包含时间线、收藏标注、季节主题等基础框架 2. 替换hive为社区维护的hive_ce包,修复依赖兼容问题 3. 统一替换"开发中"提示为"当前设备不支持",优化用户提示文案 4. 新增多项功能开关与特性标志,统一管理不可用功能提示 5. 完善用户账户洞察系统,新增头像审核中状态检测 6. 优化TTS语音朗读服务,修复Android端引擎初始化问题 7. 重构知识图谱缩放手势逻辑,解决缩放不跟手问题 8. 新增精灵头像组件,替换默认聊天头像样式 9. 新增外部链接跳转确认弹窗,提升使用安全性 10. 升级后端API接口,新增签到配置获取与补签积分规则动态读取 11. 完善多语言翻译覆盖率限制,非中文语言仅显示最高50%进度 12. 新增HTTP缓存拦截器,优化网络请求性能 13. 新增恢复出厂设置选项,完善数据管理功能 同时修复了多处代码细节问题:简化字符串拼接、优化布局代码、移除多余代码等。
1519 lines
39 KiB
HTML
1519 lines
39 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<!--
|
||
创建时间: 2026-05-27
|
||
更新时间: 2026-05-27
|
||
名称: 闲情逸致 — 卡片详情Sheet
|
||
作用: 模拟点击卡片后弹出的可拖拽底部Sheet详情页
|
||
上次更新: 初始创建,含拖拽交互、毛玻璃、暗色模式、标注区、外部搜索
|
||
-->
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||
<title>闲情逸致 — 卡片详情</title>
|
||
<style>
|
||
:root {
|
||
--primary: #6C63FF;
|
||
--primary-light: #8B83FF;
|
||
--accent: #4ECDC4;
|
||
--secondary: #FF6B6B;
|
||
--success: #10B981;
|
||
--warning: #F59E0B;
|
||
--error: #EF4444;
|
||
--info: #3B82F6;
|
||
|
||
--bg-primary: #FAFAFA;
|
||
--bg-secondary: #F5F5F5;
|
||
--bg-card: #FFFFFF;
|
||
--bg-elevated: #FFFFFF;
|
||
|
||
--text-primary: #1A1A2E;
|
||
--text-secondary: #6B7280;
|
||
--text-hint: #9CA3AF;
|
||
|
||
--radius-sm: 4px;
|
||
--radius-md: 8px;
|
||
--radius-lg: 12px;
|
||
--radius-xl: 16px;
|
||
--radius-2xl: 20px;
|
||
|
||
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
|
||
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
|
||
|
||
--space-xs: 4px;
|
||
--space-sm: 8px;
|
||
--space-md: 16px;
|
||
--space-lg: 24px;
|
||
--space-xl: 32px;
|
||
|
||
--spring: #4ECDC4;
|
||
--summer: #FF6B6B;
|
||
--autumn: #F59E0B;
|
||
--winter: #3B82F6;
|
||
|
||
--sheet-bg: rgba(255, 255, 255, 0.82);
|
||
--sheet-border: rgba(0, 0, 0, 0.06);
|
||
--overlay-bg: rgba(0, 0, 0, 0.35);
|
||
}
|
||
|
||
* { 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(--bg-primary);
|
||
color: var(--text-primary);
|
||
-webkit-font-smoothing: antialiased;
|
||
overflow: hidden;
|
||
height: 100vh;
|
||
width: 100vw;
|
||
}
|
||
|
||
.phone-frame {
|
||
max-width: 430px;
|
||
margin: 0 auto;
|
||
height: 100vh;
|
||
position: relative;
|
||
background: var(--bg-primary);
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* ===== 背景时间线(模糊) ===== */
|
||
.bg-timeline {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
filter: blur(8px);
|
||
-webkit-filter: blur(8px);
|
||
transform: scale(1.02);
|
||
opacity: 0.6;
|
||
overflow: hidden;
|
||
z-index: 1;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.bg-timeline .appbar {
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 100;
|
||
backdrop-filter: blur(20px);
|
||
-webkit-backdrop-filter: blur(20px);
|
||
background: rgba(250, 250, 250, 0.78);
|
||
border-bottom: 0.5px solid rgba(0,0,0,0.08);
|
||
padding: 12px var(--space-md);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.bg-timeline .appbar-title {
|
||
font-size: 17px;
|
||
font-weight: 600;
|
||
letter-spacing: -0.2px;
|
||
}
|
||
|
||
.bg-timeline .appbar-subtitle {
|
||
font-size: 12px;
|
||
color: var(--text-hint);
|
||
margin-top: 1px;
|
||
}
|
||
|
||
.bg-timeline .timeline-line {
|
||
position: absolute;
|
||
left: 50%;
|
||
top: 60px;
|
||
bottom: 0;
|
||
width: 2px;
|
||
background: linear-gradient(to bottom, transparent, var(--primary) 5%, var(--primary) 95%, transparent);
|
||
transform: translateX(-50%);
|
||
opacity: 0.15;
|
||
}
|
||
|
||
.bg-timeline .bg-card-row {
|
||
display: flex;
|
||
gap: 10px;
|
||
margin: 16px var(--space-md);
|
||
}
|
||
|
||
.bg-timeline .bg-card-col {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.bg-timeline .bg-card {
|
||
background: var(--bg-card);
|
||
border-radius: var(--radius-lg);
|
||
box-shadow: var(--shadow-sm);
|
||
padding: 12px;
|
||
border: 0.5px solid rgba(0,0,0,0.04);
|
||
}
|
||
|
||
.bg-timeline .bg-card-title {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.bg-timeline .bg-card-desc {
|
||
font-size: 12px;
|
||
color: var(--text-secondary);
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.bg-timeline .bg-card-loc {
|
||
font-size: 11px;
|
||
color: var(--text-hint);
|
||
margin-top: 6px;
|
||
}
|
||
|
||
/* ===== 遮罩层 ===== */
|
||
.sheet-overlay {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: var(--overlay-bg);
|
||
z-index: 10;
|
||
opacity: 0;
|
||
transition: opacity 0.35s ease;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.sheet-overlay.visible {
|
||
opacity: 1;
|
||
pointer-events: auto;
|
||
}
|
||
|
||
/* ===== 底部Sheet ===== */
|
||
.bottom-sheet {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
z-index: 20;
|
||
background: var(--sheet-bg);
|
||
backdrop-filter: blur(40px) saturate(180%);
|
||
-webkit-backdrop-filter: blur(40px) saturate(180%);
|
||
border-radius: var(--radius-2xl) var(--radius-2xl) 0 0;
|
||
box-shadow: 0 -4px 30px rgba(0, 0, 0, 0.12);
|
||
border-top: 0.5px solid var(--sheet-border);
|
||
transition: height 0.35s cubic-bezier(0.32, 0.72, 0, 1);
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
will-change: height;
|
||
}
|
||
|
||
.bottom-sheet.dragging {
|
||
transition: none;
|
||
}
|
||
|
||
/* ===== 拖拽手柄 ===== */
|
||
.sheet-handle-area {
|
||
padding: 8px 0 4px;
|
||
cursor: grab;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
flex-shrink: 0;
|
||
-webkit-user-select: none;
|
||
user-select: none;
|
||
}
|
||
|
||
.sheet-handle-area:active {
|
||
cursor: grabbing;
|
||
}
|
||
|
||
.sheet-handle {
|
||
width: 36px;
|
||
height: 5px;
|
||
border-radius: 3px;
|
||
background: rgba(0, 0, 0, 0.18);
|
||
transition: background 0.2s, width 0.2s;
|
||
}
|
||
|
||
.sheet-handle-area:hover .sheet-handle {
|
||
width: 42px;
|
||
background: rgba(0, 0, 0, 0.28);
|
||
}
|
||
|
||
/* ===== Sheet Header ===== */
|
||
.sheet-header {
|
||
padding: 4px var(--space-lg) var(--space-md);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.sheet-header-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-sm);
|
||
}
|
||
|
||
.sheet-back-btn {
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: 50%;
|
||
background: var(--bg-secondary);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 16px;
|
||
cursor: pointer;
|
||
border: none;
|
||
color: var(--text-primary);
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.sheet-back-btn:active {
|
||
transform: scale(0.92);
|
||
background: rgba(0,0,0,0.06);
|
||
}
|
||
|
||
.sheet-title {
|
||
font-size: 17px;
|
||
font-weight: 600;
|
||
letter-spacing: -0.2px;
|
||
}
|
||
|
||
.sheet-header-actions {
|
||
display: flex;
|
||
gap: var(--space-sm);
|
||
}
|
||
|
||
.sheet-header-btn {
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: 50%;
|
||
background: var(--bg-secondary);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
border: none;
|
||
color: var(--text-secondary);
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.sheet-header-btn:active {
|
||
transform: scale(0.92);
|
||
}
|
||
|
||
/* ===== Sheet Content (scrollable) ===== */
|
||
.sheet-content {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
overflow-x: hidden;
|
||
padding: 0 var(--space-lg) var(--space-xl);
|
||
-webkit-overflow-scrolling: touch;
|
||
overscroll-behavior-y: contain;
|
||
}
|
||
|
||
.sheet-content::-webkit-scrollbar {
|
||
width: 3px;
|
||
}
|
||
|
||
.sheet-content::-webkit-scrollbar-thumb {
|
||
background: rgba(0,0,0,0.12);
|
||
border-radius: 3px;
|
||
}
|
||
|
||
/* ===== 卡片详情 Hero ===== */
|
||
.detail-hero {
|
||
position: relative;
|
||
border-radius: var(--radius-xl);
|
||
overflow: hidden;
|
||
margin-bottom: var(--space-lg);
|
||
}
|
||
|
||
.detail-hero-bg {
|
||
height: 140px;
|
||
background: linear-gradient(135deg, #FF6B6B 0%, #ee5a24 50%, #f0932b 100%);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: relative;
|
||
}
|
||
|
||
.detail-hero-bg::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: -30px;
|
||
right: -30px;
|
||
width: 120px;
|
||
height: 120px;
|
||
border-radius: 50%;
|
||
background: rgba(255,255,255,0.1);
|
||
}
|
||
|
||
.detail-hero-bg::before {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: -20px;
|
||
left: -20px;
|
||
width: 80px;
|
||
height: 80px;
|
||
border-radius: 50%;
|
||
background: rgba(255,255,255,0.08);
|
||
}
|
||
|
||
.detail-hero-emoji {
|
||
font-size: 56px;
|
||
position: relative;
|
||
z-index: 2;
|
||
filter: drop-shadow(0 4px 8px rgba(0,0,0,0.15));
|
||
}
|
||
|
||
.detail-hero-overlay {
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
padding: var(--space-md) var(--space-lg);
|
||
background: linear-gradient(transparent, rgba(0,0,0,0.45));
|
||
display: flex;
|
||
align-items: flex-end;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.detail-hero-title {
|
||
font-size: 22px;
|
||
font-weight: 700;
|
||
color: white;
|
||
text-shadow: 0 1px 4px rgba(0,0,0,0.3);
|
||
}
|
||
|
||
.detail-hero-season {
|
||
font-size: 12px;
|
||
padding: 3px 10px;
|
||
border-radius: 12px;
|
||
background: rgba(255,255,255,0.25);
|
||
backdrop-filter: blur(10px);
|
||
color: white;
|
||
font-weight: 600;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* ===== 信息区 ===== */
|
||
.detail-section {
|
||
margin-bottom: var(--space-lg);
|
||
}
|
||
|
||
.detail-section-title {
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
color: var(--text-hint);
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
margin-bottom: var(--space-sm);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-xs);
|
||
}
|
||
|
||
.detail-desc {
|
||
font-size: 15px;
|
||
color: var(--text-primary);
|
||
line-height: 1.6;
|
||
margin-bottom: var(--space-md);
|
||
}
|
||
|
||
/* ===== 信息网格 ===== */
|
||
.info-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: var(--space-sm);
|
||
}
|
||
|
||
.info-item {
|
||
background: var(--bg-secondary);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--space-md);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-sm);
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.info-item:active {
|
||
transform: scale(0.98);
|
||
}
|
||
|
||
.info-item-icon {
|
||
font-size: 20px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.info-item-content {
|
||
min-width: 0;
|
||
}
|
||
|
||
.info-item-label {
|
||
font-size: 11px;
|
||
color: var(--text-hint);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.info-item-value {
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
margin-top: 1px;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.info-item.full-width {
|
||
grid-column: 1 / -1;
|
||
}
|
||
|
||
/* ===== 风险提示 ===== */
|
||
.risk-banner {
|
||
background: rgba(239, 68, 68, 0.08);
|
||
border: 1px solid rgba(239, 68, 68, 0.15);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--space-md);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-sm);
|
||
margin-bottom: var(--space-lg);
|
||
}
|
||
|
||
.risk-banner-icon {
|
||
font-size: 20px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.risk-banner-text {
|
||
font-size: 13px;
|
||
color: var(--error);
|
||
font-weight: 500;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
/* ===== 季节色标签 ===== */
|
||
.season-tags {
|
||
display: flex;
|
||
gap: var(--space-sm);
|
||
flex-wrap: wrap;
|
||
margin-bottom: var(--space-lg);
|
||
}
|
||
|
||
.season-tag {
|
||
font-size: 12px;
|
||
padding: 5px 12px;
|
||
border-radius: 14px;
|
||
font-weight: 600;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
transition: all 0.2s;
|
||
cursor: default;
|
||
}
|
||
|
||
.season-tag:active {
|
||
transform: scale(0.95);
|
||
}
|
||
|
||
.season-tag-summer {
|
||
background: rgba(255,107,107,0.12);
|
||
color: var(--summer);
|
||
}
|
||
|
||
.season-tag-food {
|
||
background: rgba(245,158,11,0.12);
|
||
color: var(--warning);
|
||
}
|
||
|
||
.season-tag-early-summer {
|
||
background: rgba(78,205,196,0.12);
|
||
color: var(--accent);
|
||
}
|
||
|
||
.season-tag-fruit {
|
||
background: rgba(108,99,255,0.12);
|
||
color: var(--primary);
|
||
}
|
||
|
||
/* ===== 操作按钮区 ===== */
|
||
.action-buttons {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: var(--space-sm);
|
||
margin-bottom: var(--space-lg);
|
||
}
|
||
|
||
.action-card {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: var(--space-md) var(--space-xs);
|
||
border-radius: var(--radius-lg);
|
||
background: var(--bg-secondary);
|
||
cursor: pointer;
|
||
border: none;
|
||
transition: all 0.2s;
|
||
-webkit-user-select: none;
|
||
user-select: none;
|
||
}
|
||
|
||
.action-card:active {
|
||
transform: scale(0.94);
|
||
}
|
||
|
||
.action-card.active {
|
||
background: rgba(108,99,255,0.1);
|
||
}
|
||
|
||
.action-card-icon {
|
||
font-size: 22px;
|
||
}
|
||
|
||
.action-card-label {
|
||
font-size: 11px;
|
||
font-weight: 500;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.action-card.active .action-card-label {
|
||
color: var(--primary);
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* ===== 多选标注区 ===== */
|
||
.annotation-area {
|
||
margin-bottom: var(--space-lg);
|
||
}
|
||
|
||
.annotation-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: var(--space-sm);
|
||
}
|
||
|
||
.annotation-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 8px 10px;
|
||
border-radius: var(--radius-md);
|
||
background: var(--bg-secondary);
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
border: 1.5px solid transparent;
|
||
-webkit-user-select: none;
|
||
user-select: none;
|
||
}
|
||
|
||
.annotation-item:active {
|
||
transform: scale(0.96);
|
||
}
|
||
|
||
.annotation-item.checked {
|
||
background: rgba(108,99,255,0.08);
|
||
border-color: rgba(108,99,255,0.3);
|
||
}
|
||
|
||
.annotation-checkbox {
|
||
width: 18px;
|
||
height: 18px;
|
||
border-radius: 5px;
|
||
border: 2px solid var(--text-hint);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
transition: all 0.2s;
|
||
font-size: 11px;
|
||
color: transparent;
|
||
}
|
||
|
||
.annotation-item.checked .annotation-checkbox {
|
||
background: var(--primary);
|
||
border-color: var(--primary);
|
||
color: white;
|
||
}
|
||
|
||
.annotation-label {
|
||
font-size: 12px;
|
||
color: var(--text-secondary);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.annotation-item.checked .annotation-label {
|
||
color: var(--primary);
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* ===== 已选标注展示 ===== */
|
||
.selected-annotations {
|
||
display: flex;
|
||
gap: 6px;
|
||
flex-wrap: wrap;
|
||
margin-top: var(--space-sm);
|
||
min-height: 28px;
|
||
}
|
||
|
||
.selected-tag {
|
||
font-size: 11px;
|
||
padding: 3px 10px;
|
||
border-radius: 10px;
|
||
background: rgba(108,99,255,0.1);
|
||
color: var(--primary);
|
||
font-weight: 600;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
animation: tagAppear 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||
}
|
||
|
||
@keyframes tagAppear {
|
||
from { opacity: 0; transform: scale(0.8); }
|
||
to { opacity: 1; transform: scale(1); }
|
||
}
|
||
|
||
.selected-tag-remove {
|
||
cursor: pointer;
|
||
font-size: 10px;
|
||
opacity: 0.6;
|
||
transition: opacity 0.2s;
|
||
}
|
||
|
||
.selected-tag-remove:hover {
|
||
opacity: 1;
|
||
}
|
||
|
||
/* ===== 外部搜索按钮组 ===== */
|
||
.search-group {
|
||
margin-bottom: var(--space-lg);
|
||
}
|
||
|
||
.search-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(5, 1fr);
|
||
gap: var(--space-sm);
|
||
}
|
||
|
||
.search-btn {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 5px;
|
||
padding: 10px 4px;
|
||
border-radius: var(--radius-lg);
|
||
background: var(--bg-secondary);
|
||
cursor: pointer;
|
||
border: 1px solid transparent;
|
||
transition: all 0.2s;
|
||
-webkit-user-select: none;
|
||
user-select: none;
|
||
}
|
||
|
||
.search-btn:active {
|
||
transform: scale(0.94);
|
||
border-color: rgba(108,99,255,0.2);
|
||
}
|
||
|
||
.search-btn-icon {
|
||
font-size: 24px;
|
||
}
|
||
|
||
.search-btn-name {
|
||
font-size: 10px;
|
||
font-weight: 500;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
/* ===== 相关推荐 ===== */
|
||
.recommend-list {
|
||
display: flex;
|
||
gap: var(--space-sm);
|
||
overflow-x: auto;
|
||
padding-bottom: var(--space-sm);
|
||
scroll-snap-type: x mandatory;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
.recommend-list::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
.recommend-card {
|
||
flex-shrink: 0;
|
||
width: 150px;
|
||
background: var(--bg-secondary);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--space-md);
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
scroll-snap-align: start;
|
||
border: 0.5px solid rgba(0,0,0,0.04);
|
||
}
|
||
|
||
.recommend-card:active {
|
||
transform: scale(0.96);
|
||
}
|
||
|
||
.recommend-card-emoji {
|
||
font-size: 28px;
|
||
margin-bottom: 6px;
|
||
}
|
||
|
||
.recommend-card-title {
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
margin-bottom: 3px;
|
||
}
|
||
|
||
.recommend-card-desc {
|
||
font-size: 11px;
|
||
color: var(--text-hint);
|
||
line-height: 1.3;
|
||
}
|
||
|
||
.recommend-card-season {
|
||
font-size: 10px;
|
||
padding: 2px 6px;
|
||
border-radius: 6px;
|
||
margin-top: 6px;
|
||
display: inline-block;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.rec-season-summer {
|
||
background: rgba(255,107,107,0.12);
|
||
color: var(--summer);
|
||
}
|
||
|
||
.rec-season-spring {
|
||
background: rgba(78,205,196,0.12);
|
||
color: var(--spring);
|
||
}
|
||
|
||
/* ===== Toast 提示 ===== */
|
||
.toast {
|
||
position: fixed;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%) scale(0.85);
|
||
background: rgba(0,0,0,0.78);
|
||
backdrop-filter: blur(10px);
|
||
color: white;
|
||
padding: 14px 24px;
|
||
border-radius: var(--radius-lg);
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
z-index: 100;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||
text-align: center;
|
||
max-width: 260px;
|
||
}
|
||
|
||
.toast.show {
|
||
opacity: 1;
|
||
transform: translate(-50%, -50%) scale(1);
|
||
}
|
||
|
||
/* ===== 分隔线 ===== */
|
||
.divider {
|
||
height: 0.5px;
|
||
background: var(--sheet-border);
|
||
margin: var(--space-md) 0;
|
||
}
|
||
|
||
/* ===== 底部安全区 ===== */
|
||
.bottom-safe {
|
||
height: env(safe-area-inset-bottom, 0px);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* ===== 暗色模式 ===== */
|
||
@media (prefers-color-scheme: dark) {
|
||
:root {
|
||
--bg-primary: #1A1A2E;
|
||
--bg-secondary: #16213E;
|
||
--bg-card: #2D2D44;
|
||
--bg-elevated: #333355;
|
||
--text-primary: #E5E5E5;
|
||
--text-secondary: #9CA3AF;
|
||
--text-hint: #6B7280;
|
||
--sheet-bg: rgba(45, 45, 68, 0.85);
|
||
--sheet-border: rgba(255,255,255,0.06);
|
||
--overlay-bg: rgba(0, 0, 0, 0.55);
|
||
}
|
||
|
||
.sheet-handle {
|
||
background: rgba(255, 255, 255, 0.25);
|
||
}
|
||
|
||
.sheet-handle-area:hover .sheet-handle {
|
||
background: rgba(255, 255, 255, 0.4);
|
||
}
|
||
|
||
.bg-timeline .appbar {
|
||
background: rgba(26,26,46,0.78);
|
||
border-bottom-color: rgba(255,255,255,0.06);
|
||
}
|
||
|
||
.bg-timeline .bg-card {
|
||
border-color: rgba(255,255,255,0.06);
|
||
}
|
||
|
||
.risk-banner {
|
||
background: rgba(239, 68, 68, 0.12);
|
||
border-color: rgba(239, 68, 68, 0.2);
|
||
}
|
||
|
||
.info-item {
|
||
background: var(--bg-secondary);
|
||
}
|
||
|
||
.sheet-content::-webkit-scrollbar-thumb {
|
||
background: rgba(255,255,255,0.15);
|
||
}
|
||
}
|
||
|
||
body.dark-mode {
|
||
--bg-primary: #1A1A2E;
|
||
--bg-secondary: #16213E;
|
||
--bg-card: #2D2D44;
|
||
--bg-elevated: #333355;
|
||
--text-primary: #E5E5E5;
|
||
--text-secondary: #9CA3AF;
|
||
--text-hint: #6B7280;
|
||
--sheet-bg: rgba(45, 45, 68, 0.85);
|
||
--sheet-border: rgba(255,255,255,0.06);
|
||
--overlay-bg: rgba(0, 0, 0, 0.55);
|
||
}
|
||
|
||
body.dark-mode .sheet-handle {
|
||
background: rgba(255, 255, 255, 0.25);
|
||
}
|
||
|
||
body.dark-mode .sheet-handle-area:hover .sheet-handle {
|
||
background: rgba(255, 255, 255, 0.4);
|
||
}
|
||
|
||
body.dark-mode .bg-timeline .appbar {
|
||
background: rgba(26,26,46,0.78);
|
||
border-bottom-color: rgba(255,255,255,0.06);
|
||
}
|
||
|
||
body.dark-mode .bg-timeline .bg-card {
|
||
border-color: rgba(255,255,255,0.06);
|
||
}
|
||
|
||
body.dark-mode .risk-banner {
|
||
background: rgba(239, 68, 68, 0.12);
|
||
border-color: rgba(239, 68, 68, 0.2);
|
||
}
|
||
|
||
body.dark-mode .sheet-content::-webkit-scrollbar-thumb {
|
||
background: rgba(255,255,255,0.15);
|
||
}
|
||
|
||
/* ===== 入场动画 ===== */
|
||
.sheet-enter {
|
||
animation: sheetSlideUp 0.45s cubic-bezier(0.32, 0.72, 0, 1) forwards;
|
||
}
|
||
|
||
@keyframes sheetSlideUp {
|
||
from { transform: translateY(100%); }
|
||
to { transform: translateY(0); }
|
||
}
|
||
|
||
.overlay-enter {
|
||
animation: overlayFadeIn 0.35s ease forwards;
|
||
}
|
||
|
||
@keyframes overlayFadeIn {
|
||
from { opacity: 0; }
|
||
to { opacity: 1; }
|
||
}
|
||
|
||
/* ===== 调试面板 ===== */
|
||
.debug-panel {
|
||
position: fixed;
|
||
top: 8px;
|
||
right: 8px;
|
||
z-index: 200;
|
||
display: flex;
|
||
gap: 6px;
|
||
}
|
||
|
||
.debug-btn {
|
||
font-size: 11px;
|
||
padding: 4px 10px;
|
||
border-radius: 8px;
|
||
background: rgba(0,0,0,0.6);
|
||
color: white;
|
||
border: none;
|
||
cursor: pointer;
|
||
backdrop-filter: blur(10px);
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.debug-btn:active {
|
||
transform: scale(0.95);
|
||
}
|
||
|
||
.debug-info {
|
||
position: fixed;
|
||
bottom: 8px;
|
||
right: 8px;
|
||
z-index: 200;
|
||
font-size: 10px;
|
||
padding: 4px 8px;
|
||
border-radius: 6px;
|
||
background: rgba(0,0,0,0.5);
|
||
color: rgba(255,255,255,0.7);
|
||
backdrop-filter: blur(10px);
|
||
font-family: 'SF Mono', Menlo, monospace;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="phone-frame" id="phoneFrame">
|
||
|
||
<!-- 背景时间线(模糊) -->
|
||
<div class="bg-timeline">
|
||
<div class="appbar">
|
||
<div>
|
||
<div class="appbar-title">🌸 闲情逸致</div>
|
||
<div class="appbar-subtitle">闲时与你立黄昏,灶前笑问粥可温</div>
|
||
</div>
|
||
</div>
|
||
<div class="timeline-line"></div>
|
||
<div class="bg-card-row">
|
||
<div class="bg-card-col">
|
||
<div class="bg-card">
|
||
<div class="bg-card-title">杨梅季 🫐</div>
|
||
<div class="bg-card-desc">仙居杨梅·东魁·荸荠种</div>
|
||
<div class="bg-card-loc">📍 浙江·仙居</div>
|
||
</div>
|
||
</div>
|
||
<div class="bg-card-col">
|
||
<div class="bg-card">
|
||
<div class="bg-card-title">西湖夜游 🌙</div>
|
||
<div class="bg-card-desc">印象西湖·断桥残雪</div>
|
||
<div class="bg-card-loc">📍 浙江·杭州</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="bg-card-row">
|
||
<div class="bg-card-col">
|
||
<div class="bg-card">
|
||
<div class="bg-card-title">小龙虾 🦞</div>
|
||
<div class="bg-card-desc">盱眙十三香·潜江油焖</div>
|
||
<div class="bg-card-loc">📍 江苏·盱眙</div>
|
||
</div>
|
||
</div>
|
||
<div class="bg-card-col">
|
||
<div class="bg-card">
|
||
<div class="bg-card-title">薰衣草花海 💜</div>
|
||
<div class="bg-card-desc">伊犁河谷薰衣草初开</div>
|
||
<div class="bg-card-loc">📍 新疆·伊犁</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 遮罩层 -->
|
||
<div class="sheet-overlay" id="sheetOverlay"></div>
|
||
|
||
<!-- 底部Sheet -->
|
||
<div class="bottom-sheet sheet-enter" id="bottomSheet">
|
||
<!-- 拖拽手柄 -->
|
||
<div class="sheet-handle-area" id="sheetHandle">
|
||
<div class="sheet-handle"></div>
|
||
</div>
|
||
|
||
<!-- Sheet Header -->
|
||
<div class="sheet-header">
|
||
<div class="sheet-header-left">
|
||
<button class="sheet-back-btn" onclick="goBack()" title="返回">‹</button>
|
||
<span class="sheet-title">卡片详情</span>
|
||
</div>
|
||
<div class="sheet-header-actions">
|
||
<button class="sheet-header-btn" onclick="toggleDarkMode()" title="暗色模式" id="darkBtn">🌙</button>
|
||
<button class="sheet-header-btn" onclick="showToast('更多操作开发中…')" title="更多">⋯</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sheet Content -->
|
||
<div class="sheet-content" id="sheetContent">
|
||
|
||
<!-- Hero区 -->
|
||
<div class="detail-hero">
|
||
<div class="detail-hero-bg">
|
||
<span class="detail-hero-emoji">🫐</span>
|
||
<div class="detail-hero-overlay">
|
||
<div class="detail-hero-title">杨梅季</div>
|
||
<span class="detail-hero-season">☀️ 夏季限定</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 描述 -->
|
||
<div class="detail-desc">
|
||
仙居杨梅·东魁·荸荠种,酸甜多汁,初夏限定美味。每年6月中上旬为最佳采摘期,果大核小,汁水丰盈,是浙江仙居的金字招牌。
|
||
</div>
|
||
|
||
<!-- 季节色标签 -->
|
||
<div class="season-tags">
|
||
<span class="season-tag season-tag-summer">☀️ 夏</span>
|
||
<span class="season-tag season-tag-food">🍜 美食</span>
|
||
<span class="season-tag season-tag-early-summer">🌿 初夏限定</span>
|
||
<span class="season-tag season-tag-fruit">🍇 水果</span>
|
||
<span class="season-tag season-tag-food">🫐 杨梅</span>
|
||
</div>
|
||
|
||
<!-- 信息网格 -->
|
||
<div class="detail-section">
|
||
<div class="detail-section-title">📋 基本信息</div>
|
||
<div class="info-grid">
|
||
<div class="info-item">
|
||
<span class="info-item-icon">📍</span>
|
||
<div class="info-item-content">
|
||
<div class="info-item-label">地点</div>
|
||
<div class="info-item-value">浙江·仙居</div>
|
||
</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-item-icon">🏔️</span>
|
||
<div class="info-item-content">
|
||
<div class="info-item-label">海拔</div>
|
||
<div class="info-item-value">约50m</div>
|
||
</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-item-icon">🌅</span>
|
||
<div class="info-item-content">
|
||
<div class="info-item-label">日出</div>
|
||
<div class="info-item-value">05:12</div>
|
||
</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-item-icon">🌇</span>
|
||
<div class="info-item-content">
|
||
<div class="info-item-label">日落</div>
|
||
<div class="info-item-value">19:12</div>
|
||
</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-item-icon">💰</span>
|
||
<div class="info-item-content">
|
||
<div class="info-item-label">价格类型</div>
|
||
<div class="info-item-value" style="color: var(--success);">免费</div>
|
||
</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-item-icon">📅</span>
|
||
<div class="info-item-content">
|
||
<div class="info-item-label">最佳时期</div>
|
||
<div class="info-item-value">6月中上旬</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 风险提示 -->
|
||
<div class="risk-banner">
|
||
<span class="risk-banner-icon">⚠️</span>
|
||
<span class="risk-banner-text">杨梅采摘注意防蚊虫叮咬,雨天山路湿滑请小心行走。杨梅不宜与黄瓜、牛奶同食。</span>
|
||
</div>
|
||
|
||
<div class="divider"></div>
|
||
|
||
<!-- 操作按钮区 -->
|
||
<div class="detail-section">
|
||
<div class="detail-section-title">⚡ 快捷操作</div>
|
||
<div class="action-buttons">
|
||
<div class="action-card" onclick="toggleAction(this, '已收藏到笔记')">
|
||
<span class="action-card-icon">🔖</span>
|
||
<span class="action-card-label">收藏笔记</span>
|
||
</div>
|
||
<div class="action-card" onclick="shareCard()">
|
||
<span class="action-card-icon">📤</span>
|
||
<span class="action-card-label">分享卡片</span>
|
||
</div>
|
||
<div class="action-card" onclick="showToast('正在跳转外部搜索…')">
|
||
<span class="action-card-icon">🔍</span>
|
||
<span class="action-card-label">外部搜索</span>
|
||
</div>
|
||
<div class="action-card" onclick="toggleAction(this, '标注已添加')">
|
||
<span class="action-card-icon">🏷️</span>
|
||
<span class="action-card-label">添加标注</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="divider"></div>
|
||
|
||
<!-- 多选标注区 -->
|
||
<div class="annotation-area">
|
||
<div class="detail-section-title">🏷️ 选择标注</div>
|
||
<div class="annotation-grid" id="annotationGrid">
|
||
<div class="annotation-item" onclick="toggleAnnotation(this)">
|
||
<div class="annotation-checkbox">✓</div>
|
||
<span class="annotation-label">🫐 杨梅</span>
|
||
</div>
|
||
<div class="annotation-item" onclick="toggleAnnotation(this)">
|
||
<div class="annotation-checkbox">✓</div>
|
||
<span class="annotation-label">🌿 初夏</span>
|
||
</div>
|
||
<div class="annotation-item checked" onclick="toggleAnnotation(this)">
|
||
<div class="annotation-checkbox">✓</div>
|
||
<span class="annotation-label">🍇 水果</span>
|
||
</div>
|
||
<div class="annotation-item" onclick="toggleAnnotation(this)">
|
||
<div class="annotation-checkbox">✓</div>
|
||
<span class="annotation-label">🆓 免费</span>
|
||
</div>
|
||
<div class="annotation-item" onclick="toggleAnnotation(this)">
|
||
<div class="annotation-checkbox">✓</div>
|
||
<span class="annotation-label">👨👩👧 亲子</span>
|
||
</div>
|
||
<div class="annotation-item" onclick="toggleAnnotation(this)">
|
||
<div class="annotation-checkbox">✓</div>
|
||
<span class="annotation-label">📸 拍照</span>
|
||
</div>
|
||
<div class="annotation-item" onclick="toggleAnnotation(this)">
|
||
<div class="annotation-checkbox">✓</div>
|
||
<span class="annotation-label">🧺 采摘</span>
|
||
</div>
|
||
<div class="annotation-item" onclick="toggleAnnotation(this)">
|
||
<div class="annotation-checkbox">✓</div>
|
||
<span class="annotation-label">🚗 自驾</span>
|
||
</div>
|
||
<div class="annotation-item" onclick="toggleAnnotation(this)">
|
||
<div class="annotation-checkbox">✓</div>
|
||
<span class="annotation-label">🌧️ 雨季</span>
|
||
</div>
|
||
</div>
|
||
<!-- 已选标注展示 -->
|
||
<div class="selected-annotations" id="selectedAnnotations"></div>
|
||
</div>
|
||
|
||
<div class="divider"></div>
|
||
|
||
<!-- 外部搜索按钮组 -->
|
||
<div class="search-group">
|
||
<div class="detail-section-title">🌐 外部搜索</div>
|
||
<div class="search-grid">
|
||
<div class="search-btn" onclick="openExternal('百度')">
|
||
<span class="search-btn-icon">🔵</span>
|
||
<span class="search-btn-name">百度</span>
|
||
</div>
|
||
<div class="search-btn" onclick="openExternal('高德地图')">
|
||
<span class="search-btn-icon">🗺️</span>
|
||
<span class="search-btn-name">高德</span>
|
||
</div>
|
||
<div class="search-btn" onclick="openExternal('大众点评')">
|
||
<span class="search-btn-icon">⭐</span>
|
||
<span class="search-btn-name">点评</span>
|
||
</div>
|
||
<div class="search-btn" onclick="openExternal('小红书')">
|
||
<span class="search-btn-icon">📕</span>
|
||
<span class="search-btn-name">小红书</span>
|
||
</div>
|
||
<div class="search-btn" onclick="openExternal('抖音')">
|
||
<span class="search-btn-icon">🎵</span>
|
||
<span class="search-btn-name">抖音</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="divider"></div>
|
||
|
||
<!-- 相关推荐 -->
|
||
<div class="detail-section">
|
||
<div class="detail-section-title">💡 相关推荐</div>
|
||
<div class="recommend-list">
|
||
<div class="recommend-card" onclick="showToast('查看: 荔枝初上市')">
|
||
<div class="recommend-card-emoji">🫒</div>
|
||
<div class="recommend-card-title">荔枝初上市</div>
|
||
<div class="recommend-card-desc">妃子笑·桂味·糯米糍</div>
|
||
<span class="recommend-card-season rec-season-summer">☀️ 夏</span>
|
||
</div>
|
||
<div class="recommend-card" onclick="showToast('查看: 西湖夜游')">
|
||
<div class="recommend-card-emoji">🌙</div>
|
||
<div class="recommend-card-title">西湖夜游</div>
|
||
<div class="recommend-card-desc">印象西湖·断桥残雪</div>
|
||
<span class="recommend-card-season rec-season-summer">☀️ 夏</span>
|
||
</div>
|
||
<div class="recommend-card" onclick="showToast('查看: 龙井问茶')">
|
||
<div class="recommend-card-emoji">🍵</div>
|
||
<div class="recommend-card-title">龙井问茶</div>
|
||
<div class="recommend-card-desc">明前龙井·虎跑泉</div>
|
||
<span class="recommend-card-season rec-season-spring">🌿 春</span>
|
||
</div>
|
||
<div class="recommend-card" onclick="showToast('查看: 乌镇水乡')">
|
||
<div class="recommend-card-emoji">🏘️</div>
|
||
<div class="recommend-card-title">乌镇水乡</div>
|
||
<div class="recommend-card-desc">江南水乡·夜游西栅</div>
|
||
<span class="recommend-card-season rec-season-spring">🌿 春</span>
|
||
</div>
|
||
<div class="recommend-card" onclick="showToast('查看: 小龙虾')">
|
||
<div class="recommend-card-emoji">🦞</div>
|
||
<div class="recommend-card-title">小龙虾季</div>
|
||
<div class="recommend-card-desc">盱眙十三香·潜江油焖</div>
|
||
<span class="recommend-card-season rec-season-summer">☀️ 夏</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 底部安全区占位 -->
|
||
<div class="bottom-safe"></div>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /phone-frame -->
|
||
|
||
<!-- Toast -->
|
||
<div class="toast" id="toast"></div>
|
||
|
||
<!-- 调试面板 -->
|
||
<div class="debug-panel">
|
||
<button class="debug-btn" onclick="collapseSheet()">收起</button>
|
||
<button class="debug-btn" onclick="expandSheet()">展开</button>
|
||
<button class="debug-btn" onclick="toggleDarkMode()">🌓</button>
|
||
</div>
|
||
<div class="debug-info" id="debugInfo">Sheet: 33%</div>
|
||
|
||
<script>
|
||
/* ===== 常量与状态 ===== */
|
||
var MIN_HEIGHT_RATIO = 0.33;
|
||
var MAX_HEIGHT_RATIO = 0.90;
|
||
var DISMISS_RATIO = 0.15;
|
||
|
||
var sheet = document.getElementById('bottomSheet');
|
||
var overlay = document.getElementById('sheetOverlay');
|
||
var handle = document.getElementById('sheetHandle');
|
||
var content = document.getElementById('sheetContent');
|
||
var debugInfo = document.getElementById('debugInfo');
|
||
|
||
var currentRatio = MIN_HEIGHT_RATIO;
|
||
var isDragging = false;
|
||
var startY = 0;
|
||
var startHeight = 0;
|
||
|
||
/* ===== 初始化 ===== */
|
||
function init() {
|
||
setSheetHeight(currentRatio);
|
||
overlay.classList.add('visible', 'overlay-enter');
|
||
updateSelectedAnnotations();
|
||
}
|
||
|
||
/* ===== 设置Sheet高度 ===== */
|
||
function setSheetHeight(ratio) {
|
||
ratio = Math.max(MIN_HEIGHT_RATIO, Math.min(MAX_HEIGHT_RATIO, ratio));
|
||
currentRatio = ratio;
|
||
var vh = window.innerHeight;
|
||
var h = Math.round(vh * ratio);
|
||
sheet.style.height = h + 'px';
|
||
updateDebugInfo();
|
||
}
|
||
|
||
/* ===== 拖拽交互 ===== */
|
||
function onDragStart(clientY) {
|
||
isDragging = true;
|
||
startY = clientY;
|
||
startHeight = sheet.offsetHeight;
|
||
sheet.classList.add('dragging');
|
||
}
|
||
|
||
function onDragMove(clientY) {
|
||
if (!isDragging) return;
|
||
var deltaY = startY - clientY;
|
||
var newHeight = startHeight + deltaY;
|
||
var vh = window.innerHeight;
|
||
var newRatio = newHeight / vh;
|
||
setSheetHeight(newRatio);
|
||
}
|
||
|
||
function onDragEnd() {
|
||
if (!isDragging) return;
|
||
isDragging = false;
|
||
sheet.classList.remove('dragging');
|
||
|
||
if (currentRatio < DISMISS_RATIO) {
|
||
goBack();
|
||
} else if (currentRatio < 0.45) {
|
||
animateSheetTo(MIN_HEIGHT_RATIO);
|
||
} else if (currentRatio > 0.7) {
|
||
animateSheetTo(MAX_HEIGHT_RATIO);
|
||
} else {
|
||
animateSheetTo(currentRatio);
|
||
}
|
||
}
|
||
|
||
/* ===== 鼠标事件 ===== */
|
||
handle.addEventListener('mousedown', function(e) {
|
||
e.preventDefault();
|
||
onDragStart(e.clientY);
|
||
});
|
||
|
||
document.addEventListener('mousemove', function(e) {
|
||
onDragMove(e.clientY);
|
||
});
|
||
|
||
document.addEventListener('mouseup', function() {
|
||
onDragEnd();
|
||
});
|
||
|
||
/* ===== 触摸事件 ===== */
|
||
handle.addEventListener('touchstart', function(e) {
|
||
e.preventDefault();
|
||
onDragStart(e.touches[0].clientY);
|
||
}, { passive: false });
|
||
|
||
document.addEventListener('touchmove', function(e) {
|
||
if (isDragging) {
|
||
e.preventDefault();
|
||
onDragMove(e.touches[0].clientY);
|
||
}
|
||
}, { passive: false });
|
||
|
||
document.addEventListener('touchend', function() {
|
||
onDragEnd();
|
||
});
|
||
|
||
/* ===== 动画过渡到目标高度 ===== */
|
||
function animateSheetTo(targetRatio) {
|
||
sheet.classList.remove('dragging');
|
||
setSheetHeight(targetRatio);
|
||
}
|
||
|
||
/* ===== 快捷操作 ===== */
|
||
function expandSheet() {
|
||
animateSheetTo(MAX_HEIGHT_RATIO);
|
||
}
|
||
|
||
function collapseSheet() {
|
||
animateSheetTo(MIN_HEIGHT_RATIO);
|
||
}
|
||
|
||
/* ===== 返回 ===== */
|
||
function goBack() {
|
||
sheet.style.transition = 'transform 0.35s cubic-bezier(0.32, 0.72, 0, 1)';
|
||
sheet.style.transform = 'translateY(100%)';
|
||
overlay.style.transition = 'opacity 0.3s ease';
|
||
overlay.style.opacity = '0';
|
||
setTimeout(function() {
|
||
window.location.href = 'leisure_timeline.html';
|
||
}, 350);
|
||
}
|
||
|
||
/* ===== 暗色模式 ===== */
|
||
function toggleDarkMode() {
|
||
document.body.classList.toggle('dark-mode');
|
||
var btn = document.getElementById('darkBtn');
|
||
btn.innerHTML = document.body.classList.contains('dark-mode') ? '☀️' : '🌙';
|
||
}
|
||
|
||
/* ===== 操作按钮 ===== */
|
||
function toggleAction(el, msg) {
|
||
el.classList.toggle('active');
|
||
if (el.classList.contains('active')) {
|
||
showToast(msg || '已操作');
|
||
}
|
||
}
|
||
|
||
function shareCard() {
|
||
showToast('正在生成分享卡片…');
|
||
setTimeout(function() {
|
||
window.location.href = 'leisure_share_card.html';
|
||
}, 800);
|
||
}
|
||
|
||
/* ===== 标注交互 ===== */
|
||
function toggleAnnotation(el) {
|
||
el.classList.toggle('checked');
|
||
updateSelectedAnnotations();
|
||
}
|
||
|
||
function updateSelectedAnnotations() {
|
||
var container = document.getElementById('selectedAnnotations');
|
||
container.innerHTML = '';
|
||
var items = document.querySelectorAll('.annotation-item.checked');
|
||
items.forEach(function(item) {
|
||
var label = item.querySelector('.annotation-label').textContent;
|
||
var tag = document.createElement('span');
|
||
tag.className = 'selected-tag';
|
||
tag.innerHTML = label + ' <span class="selected-tag-remove" onclick="removeAnnotation(this, \'' + label.trim() + '\')">✕</span>';
|
||
container.appendChild(tag);
|
||
});
|
||
}
|
||
|
||
function removeAnnotation(removeEl, labelText) {
|
||
var items = document.querySelectorAll('.annotation-item.checked');
|
||
items.forEach(function(item) {
|
||
var label = item.querySelector('.annotation-label').textContent.trim();
|
||
if (label === labelText) {
|
||
item.classList.remove('checked');
|
||
}
|
||
});
|
||
updateSelectedAnnotations();
|
||
}
|
||
|
||
/* ===== 外部搜索 ===== */
|
||
function openExternal(platform) {
|
||
var urls = {
|
||
'百度': 'https://www.baidu.com/s?wd=仙居杨梅',
|
||
'高德地图': 'https://www.amap.com/search?query=仙居杨梅',
|
||
'大众点评': 'https://www.dianping.com/search/keyword/0/0_%E6%9D%A8%E6%A2%85',
|
||
'小红书': 'https://www.xiaohongshu.com/search_result?keyword=仙居杨梅',
|
||
'抖音': 'https://www.douyin.com/search/仙居杨梅'
|
||
};
|
||
showToast('🔍 ' + platform + ': 仙居杨梅\n' + (urls[platform] || ''));
|
||
}
|
||
|
||
/* ===== Toast ===== */
|
||
var toastTimer = null;
|
||
function showToast(msg) {
|
||
var toast = document.getElementById('toast');
|
||
toast.textContent = msg;
|
||
toast.classList.add('show');
|
||
if (toastTimer) clearTimeout(toastTimer);
|
||
toastTimer = setTimeout(function() {
|
||
toast.classList.remove('show');
|
||
}, 2000);
|
||
}
|
||
|
||
/* ===== 调试信息 ===== */
|
||
function updateDebugInfo() {
|
||
var pct = Math.round(currentRatio * 100);
|
||
debugInfo.textContent = 'Sheet: ' + pct + '% | H: ' + sheet.offsetHeight + 'px';
|
||
}
|
||
|
||
/* ===== 窗口大小变化 ===== */
|
||
window.addEventListener('resize', function() {
|
||
setSheetHeight(currentRatio);
|
||
});
|
||
|
||
/* ===== 键盘快捷键 ===== */
|
||
document.addEventListener('keydown', function(e) {
|
||
if (e.key === 'Escape') goBack();
|
||
if (e.key === 'ArrowUp') expandSheet();
|
||
if (e.key === 'ArrowDown') collapseSheet();
|
||
});
|
||
|
||
/* ===== 启动 ===== */
|
||
init();
|
||
</script>
|
||
</body>
|
||
</html>
|