generated from root/feiqiu-ETL
feat:引入 TDesign 以及前端初稿
This commit is contained in:
528
Prototype/pages/board-finance.html
Normal file
528
Prototype/pages/board-finance.html
Normal file
@@ -0,0 +1,528 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>看板-财务 - 球房运营助手</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: '#0052d9',
|
||||
'primary-light': '#ecf2fe',
|
||||
success: '#00a870',
|
||||
warning: '#ed7b2f',
|
||||
error: '#e34d59',
|
||||
'gray-1': '#f3f3f3',
|
||||
'gray-2': '#eeeeee',
|
||||
'gray-3': '#e7e7e7',
|
||||
'gray-4': '#dcdcdc',
|
||||
'gray-5': '#c5c5c5',
|
||||
'gray-6': '#a6a6a6',
|
||||
'gray-7': '#8b8b8b',
|
||||
'gray-8': '#777777',
|
||||
'gray-9': '#5e5e5e',
|
||||
'gray-10': '#4b4b4b',
|
||||
'gray-11': '#393939',
|
||||
'gray-12': '#2c2c2c',
|
||||
'gray-13': '#242424',
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['Noto Sans SC', 'sans-serif'],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
padding-bottom: 80px;
|
||||
}
|
||||
.safe-area-top {
|
||||
padding-top: env(safe-area-inset-top, 44px);
|
||||
}
|
||||
.tab-active {
|
||||
color: #0052d9;
|
||||
position: relative;
|
||||
}
|
||||
.tab-active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 24px;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, #0052d9, #5b9cf8);
|
||||
border-radius: 2px;
|
||||
}
|
||||
.filter-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1000;
|
||||
}
|
||||
.filter-overlay.show {
|
||||
display: block;
|
||||
}
|
||||
.filter-dropdown {
|
||||
display: none;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: white;
|
||||
border-radius: 0 0 16px 16px;
|
||||
box-shadow: 0 8px 24px rgba(0,0,0,0.15);
|
||||
z-index: 1001;
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.filter-dropdown.show {
|
||||
display: block;
|
||||
}
|
||||
/* 二级筛选栏层级与动效 */
|
||||
#filterBar {
|
||||
overflow: hidden;
|
||||
max-height: 120px;
|
||||
transition: transform 220ms ease, opacity 220ms ease, max-height 220ms ease;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
/* 浠呯敤浜庘€滈娆¤繘鍏ラ〉闈⑩€濈殑涓嬫粦鍑虹幇锛堢敤 transition 瑙﹀彂涓€娆★級 */
|
||||
#filterBar.filter-bar-enter {
|
||||
transform: translateY(-16px);
|
||||
opacity: 0;
|
||||
}
|
||||
#filterBar.filter-bar-hidden {
|
||||
opacity: 0;
|
||||
transform: translateY(-110%);
|
||||
pointer-events: none;
|
||||
}
|
||||
@keyframes filterBarDrop {
|
||||
from { transform: translateY(-16px); opacity: 0; }
|
||||
to { transform: translateY(0); opacity: 1; }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
#filterBar { animation: none; transition: none; }
|
||||
}
|
||||
.summary-gradient {
|
||||
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen">
|
||||
<!-- 顶部导航 -->
|
||||
<div class="safe-area-top bg-white sticky top-0 z-20 shadow-sm">
|
||||
<div class="h-11 flex items-center justify-center relative border-b border-gray-2">
|
||||
<h1 class="text-base font-medium text-gray-13">看板</h1>
|
||||
</div>
|
||||
<!-- 一级 Tab -->
|
||||
<div class="flex">
|
||||
<a href="board-finance.html" class="flex-1 py-3 text-center text-sm font-medium tab-active">财务</a>
|
||||
<a href="board-customer.html" class="flex-1 py-3 text-center text-sm font-medium text-gray-7">客户</a>
|
||||
<a href="board-coach.html" class="flex-1 py-3 text-center text-sm font-medium text-gray-7">助教</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选区域(二级) -->
|
||||
<div id="filterBar" class="bg-gray-1 sticky top-[88px] z-10 px-4 py-2 border-b border-gray-2">
|
||||
<div class="bg-white rounded-2xl p-1.5 flex gap-2 shadow-sm border border-gray-2">
|
||||
<button onclick="toggleFilter('mode')" class="flex-1 px-3 py-2 bg-primary-light rounded-lg text-sm text-primary flex items-center justify-center gap-1 border border-primary/20">
|
||||
<span id="modeLabel">记账</span>
|
||||
<svg class="w-4 h-4 text-primary" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="6 9 12 15 18 9"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button onclick="toggleFilter('time')" class="flex-1 px-3 py-2 bg-gray-50 rounded-lg text-sm text-gray-10 flex items-center justify-center gap-1 border border-gray-100">
|
||||
<span id="timeLabel">本月</span>
|
||||
<svg class="w-4 h-4 text-gray-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="6 9 12 15 18 9"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button onclick="toggleFilter('area')" class="flex-1 px-3 py-2 bg-gray-50 rounded-lg text-sm text-gray-10 flex items-center justify-center gap-1 border border-gray-100">
|
||||
<span id="areaLabel">全部区域</span>
|
||||
<svg class="w-4 h-4 text-gray-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="6 9 12 15 18 9"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 遮罩层 -->
|
||||
<div id="filterOverlay" class="filter-overlay" onclick="closeAllFilters()"></div>
|
||||
|
||||
<!-- 时间筛选弹窗 -->
|
||||
<div id="timeDropdown" class="filter-dropdown">
|
||||
<div class="p-4 space-y-2">
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer flex items-center justify-between" onclick="selectTime('本月')">
|
||||
<span>本月</span>
|
||||
<svg class="w-4 h-4 text-primary hidden" id="time-check-本月" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer flex items-center justify-between" onclick="selectTime('上个月')">
|
||||
<span>上个月</span>
|
||||
<svg class="w-4 h-4 text-primary hidden" id="time-check-上个月" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer flex items-center justify-between" onclick="selectTime('最近3个月')">
|
||||
<span>最近3个月</span>
|
||||
<svg class="w-4 h-4 text-primary hidden" id="time-check-最近3个月" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer flex items-center justify-between" onclick="selectTime('最近半年')">
|
||||
<span>最近半年</span>
|
||||
<svg class="w-4 h-4 text-primary hidden" id="time-check-最近半年" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer flex items-center justify-between" onclick="selectTime('本季度')">
|
||||
<span>本季度</span>
|
||||
<svg class="w-4 h-4 text-primary hidden" id="time-check-本季度" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer flex items-center justify-between" onclick="selectTime('上个季度')">
|
||||
<span>上个季度</span>
|
||||
<svg class="w-4 h-4 text-primary hidden" id="time-check-上个季度" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer flex items-center justify-between" onclick="selectTime('本周')">
|
||||
<span>本周</span>
|
||||
<svg class="w-4 h-4 text-primary hidden" id="time-check-本周" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer flex items-center justify-between" onclick="selectTime('上周')">
|
||||
<span>上周</span>
|
||||
<svg class="w-4 h-4 text-primary hidden" id="time-check-上周" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 口径筛选弹窗 -->
|
||||
<div id="modeDropdown" class="filter-dropdown">
|
||||
<div class="p-4 space-y-2">
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectMode('记账')">记账</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectMode('实收/实付')">实收/实付</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 区域筛选弹窗 -->
|
||||
<div id="areaDropdown" class="filter-dropdown">
|
||||
<div class="p-4 space-y-2">
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectArea('全部区域')">全部区域</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer font-medium" onclick="selectArea('大厅')">大厅</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-7 hover:bg-primary/5 rounded-lg cursor-pointer pl-8" onclick="selectArea('A区')">A区</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-7 hover:bg-primary/5 rounded-lg cursor-pointer pl-8" onclick="selectArea('B区')">B区</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-7 hover:bg-primary/5 rounded-lg cursor-pointer pl-8" onclick="selectArea('C区')">C区</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer font-medium" onclick="selectArea('麻将房')">麻将房</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer font-medium" onclick="selectArea('团建房')">团建房</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 财务汇总 -->
|
||||
<div class="summary-gradient mx-4 mt-4 rounded-2xl p-5 text-white">
|
||||
<div class="grid grid-cols-3 gap-4 text-center">
|
||||
<div>
|
||||
<p class="text-white/60 text-xs mb-1">实际收入</p>
|
||||
<p class="text-xl font-bold text-green-400">28.5万</p>
|
||||
<p class="text-white/40 text-xs">预计</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-white/60 text-xs mb-1">实际支出</p>
|
||||
<p class="text-xl font-bold text-rose-400">18.2万</p>
|
||||
<p class="text-white/40 text-xs">预计</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-white/60 text-xs mb-1">净利润</p>
|
||||
<p class="text-xl font-bold text-blue-400">10.3万</p>
|
||||
<p class="text-white/40 text-xs">预计</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 指标内容 -->
|
||||
<div class="p-4 space-y-4">
|
||||
<!-- 营业数据 -->
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<span class="w-2 h-2 rounded-full bg-primary"></span>
|
||||
<h2 class="text-sm font-semibold text-gray-13">营业数据</h2>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
<div class="text-center py-3 border-r border-gray-100">
|
||||
<p class="text-lg font-bold text-gray-13">32.8万</p>
|
||||
<p class="text-xs text-gray-6 mt-1">总流水</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-r border-gray-100">
|
||||
<p class="text-lg font-bold text-gray-13">268元</p>
|
||||
<p class="text-xs text-gray-6 mt-1">客单价</p>
|
||||
</div>
|
||||
<div class="text-center py-3">
|
||||
<p class="text-lg font-bold text-gray-13">1,226</p>
|
||||
<p class="text-xs text-gray-6 mt-1">开台数</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-r border-gray-100 border-t">
|
||||
<p class="text-lg font-bold text-gray-13">892</p>
|
||||
<p class="text-xs text-gray-6 mt-1">场次</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-r border-gray-100 border-t">
|
||||
<p class="text-lg font-bold text-gray-13">2.3h</p>
|
||||
<p class="text-xs text-gray-6 mt-1">停留时长</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-t">
|
||||
<p class="text-lg font-bold text-gray-13">3.2</p>
|
||||
<p class="text-xs text-gray-6 mt-1">翻台率</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 收入构成 -->
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<span class="w-2 h-2 rounded-full bg-success"></span>
|
||||
<h2 class="text-sm font-semibold text-gray-13">收入构成</h2>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
<div class="text-center py-3 border-r border-gray-100">
|
||||
<p class="text-lg font-bold text-gray-13">12.5万</p>
|
||||
<p class="text-xs text-gray-6 mt-1">桌费</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-r border-gray-100">
|
||||
<p class="text-lg font-bold text-gray-13">8.6万</p>
|
||||
<p class="text-xs text-gray-6 mt-1">助教费</p>
|
||||
</div>
|
||||
<div class="text-center py-3">
|
||||
<p class="text-lg font-bold text-gray-13">4.2万</p>
|
||||
<p class="text-xs text-gray-6 mt-1">酒水</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-r border-gray-100 border-t">
|
||||
<p class="text-lg font-bold text-gray-13">2.8万</p>
|
||||
<p class="text-xs text-gray-6 mt-1">餐饮</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-r border-gray-100 border-t">
|
||||
<p class="text-lg font-bold text-gray-13">3.5万</p>
|
||||
<p class="text-xs text-gray-6 mt-1">包房费</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-t">
|
||||
<p class="text-lg font-bold text-gray-13">1.2万</p>
|
||||
<p class="text-xs text-gray-6 mt-1">其他</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 支出构成 -->
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<span class="w-2 h-2 rounded-full bg-error"></span>
|
||||
<h2 class="text-sm font-semibold text-gray-13">支出构成</h2>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
<div class="text-center py-3 border-r border-gray-100">
|
||||
<p class="text-lg font-bold text-gray-13">6.0万</p>
|
||||
<p class="text-xs text-gray-6 mt-1">房租</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-r border-gray-100">
|
||||
<p class="text-lg font-bold text-gray-13">1.2万</p>
|
||||
<p class="text-xs text-gray-6 mt-1">水电</p>
|
||||
</div>
|
||||
<div class="text-center py-3">
|
||||
<p class="text-lg font-bold text-gray-13">8.5万</p>
|
||||
<p class="text-xs text-gray-6 mt-1">人工</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-r border-gray-100 border-t">
|
||||
<p class="text-lg font-bold text-gray-13">0.8万</p>
|
||||
<p class="text-xs text-gray-6 mt-1">耗材</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-r border-gray-100 border-t">
|
||||
<p class="text-lg font-bold text-gray-13">1.5万</p>
|
||||
<p class="text-xs text-gray-6 mt-1">推广</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-t">
|
||||
<p class="text-lg font-bold text-gray-13">0.2万</p>
|
||||
<p class="text-xs text-gray-6 mt-1">其他</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 利润构成 -->
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<span class="w-2 h-2 rounded-full bg-warning"></span>
|
||||
<h2 class="text-sm font-semibold text-gray-13">利润构成</h2>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 gap-2">
|
||||
<div class="text-center py-3 border-r border-gray-100">
|
||||
<p class="text-lg font-bold text-gray-13">14.6万</p>
|
||||
<p class="text-xs text-gray-6 mt-1">毛利</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-r border-gray-100">
|
||||
<p class="text-lg font-bold text-gray-13">10.3万</p>
|
||||
<p class="text-xs text-gray-6 mt-1">净利</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-r border-gray-100">
|
||||
<p class="text-lg font-bold text-success">44.5%</p>
|
||||
<p class="text-xs text-gray-6 mt-1">毛利率</p>
|
||||
</div>
|
||||
<div class="text-center py-3">
|
||||
<p class="text-lg font-bold text-success">31.4%</p>
|
||||
<p class="text-xs text-gray-6 mt-1">净利率</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 悬浮助手按钮 -->
|
||||
<script src="../js/ai-float-btn.js"></script>
|
||||
|
||||
<!-- 通用底部导航 -->
|
||||
<script src="../js/bottom-nav.js"></script>
|
||||
|
||||
<script>
|
||||
let currentFilter = null;
|
||||
|
||||
function positionDropdown(dropdownEl) {
|
||||
const bar = document.getElementById('filterBar');
|
||||
if (!bar || !dropdownEl) return;
|
||||
const rect = bar.getBoundingClientRect();
|
||||
dropdownEl.style.top = `${rect.bottom}px`;
|
||||
}
|
||||
|
||||
function toggleFilter(type) {
|
||||
const overlay = document.getElementById('filterOverlay');
|
||||
const timeDropdown = document.getElementById('timeDropdown');
|
||||
const areaDropdown = document.getElementById('areaDropdown');
|
||||
const modeDropdown = document.getElementById('modeDropdown');
|
||||
|
||||
if (currentFilter === type) {
|
||||
closeAllFilters();
|
||||
return;
|
||||
}
|
||||
|
||||
closeAllFilters();
|
||||
currentFilter = type;
|
||||
overlay.classList.add('show');
|
||||
|
||||
if (type === 'time') {
|
||||
positionDropdown(timeDropdown);
|
||||
timeDropdown.classList.add('show');
|
||||
} else if (type === 'area') {
|
||||
positionDropdown(areaDropdown);
|
||||
areaDropdown.classList.add('show');
|
||||
} else if (type === 'mode') {
|
||||
positionDropdown(modeDropdown);
|
||||
modeDropdown.classList.add('show');
|
||||
}
|
||||
}
|
||||
|
||||
function closeAllFilters() {
|
||||
currentFilter = null;
|
||||
document.getElementById('filterOverlay').classList.remove('show');
|
||||
document.getElementById('timeDropdown').classList.remove('show');
|
||||
document.getElementById('areaDropdown').classList.remove('show');
|
||||
document.getElementById('modeDropdown').classList.remove('show');
|
||||
}
|
||||
|
||||
function selectTime(value) {
|
||||
document.getElementById('timeLabel').textContent = value;
|
||||
closeAllFilters();
|
||||
}
|
||||
|
||||
function selectArea(value) {
|
||||
document.getElementById('areaLabel').textContent = value;
|
||||
closeAllFilters();
|
||||
}
|
||||
|
||||
function selectMode(value) {
|
||||
document.getElementById('modeLabel').textContent = value;
|
||||
closeAllFilters();
|
||||
}
|
||||
|
||||
// 滚动时:下滑隐藏筛选栏,上滑显示(单次滚动手势结束后判断一次,避免抖动)
|
||||
(function initFilterBarScrollBehavior() {
|
||||
const bar = document.getElementById('filterBar');
|
||||
if (!bar) return;
|
||||
|
||||
const TRIGGER_DISTANCE_DOWN = 24;
|
||||
const TRIGGER_DISTANCE_UP = 12;
|
||||
const JITTER_THRESHOLD = 2;
|
||||
|
||||
let lastY = window.scrollY || 0;
|
||||
let lastDir = null; // 'down' | 'up'
|
||||
let ticking = false;
|
||||
let acc = 0;
|
||||
let lockedDir = null;
|
||||
|
||||
// 首次进入:用 transition 做一次从上到下出现
|
||||
bar.classList.add('filter-bar-enter');
|
||||
window.requestAnimationFrame(() => {
|
||||
bar.classList.remove('filter-bar-enter');
|
||||
});
|
||||
|
||||
function setVisible(visible) {
|
||||
if (visible) {
|
||||
bar.classList.remove('filter-bar-hidden');
|
||||
} else {
|
||||
if (!bar.classList.contains('filter-bar-hidden')) closeAllFilters();
|
||||
bar.classList.add('filter-bar-hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function resetGesture(y) {
|
||||
lastY = y;
|
||||
lastDir = null;
|
||||
acc = 0;
|
||||
lockedDir = null;
|
||||
}
|
||||
|
||||
function onScrollFrame() {
|
||||
const y = window.scrollY || 0;
|
||||
|
||||
// 顶部时始终显示,并重置手势
|
||||
if (y <= 8) {
|
||||
setVisible(true);
|
||||
resetGesture(y);
|
||||
return;
|
||||
}
|
||||
|
||||
const delta = y - lastY;
|
||||
if (Math.abs(delta) <= JITTER_THRESHOLD) {
|
||||
lastY = y;
|
||||
return;
|
||||
}
|
||||
|
||||
const dir = delta > 0 ? 'down' : 'up';
|
||||
if (delta !== 0) {
|
||||
if (lastDir === null) {
|
||||
lastDir = dir;
|
||||
acc = 0;
|
||||
lockedDir = null;
|
||||
} else if (dir !== lastDir) {
|
||||
// 手势中途反向:以反向前一刻为新起点,避免来回小幅抖动
|
||||
lastDir = dir;
|
||||
acc = 0;
|
||||
lockedDir = null;
|
||||
}
|
||||
}
|
||||
|
||||
lastY = y;
|
||||
|
||||
if (lockedDir === dir) return;
|
||||
acc += Math.abs(delta);
|
||||
const threshold = dir === 'up' ? TRIGGER_DISTANCE_UP : TRIGGER_DISTANCE_DOWN;
|
||||
if (acc < threshold) return;
|
||||
|
||||
setVisible(dir === 'up');
|
||||
lockedDir = dir;
|
||||
acc = 0;
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', () => {
|
||||
if (ticking) return;
|
||||
ticking = true;
|
||||
window.requestAnimationFrame(() => {
|
||||
onScrollFrame();
|
||||
ticking = false;
|
||||
});
|
||||
}, { passive: true });
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user