页面分双屏滑动: 第一屏看板/第二屏候选人列表, 左右箭头+键盘方向键+触屏滑动, 圆点指示器

This commit is contained in:
mzl92
2026-08-27 15:04:12 +08:00
parent 515273dd92
commit 2a4060ae6d
2 changed files with 52 additions and 11 deletions
+48 -9
View File
@@ -51,6 +51,15 @@ tr:hover td{background:#f8fafc;cursor:pointer}
.hidden{display:none}
.chartRow{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:12px;margin-bottom:16px}
.chartRow .panel{margin-bottom:0}
.slider{position:relative;overflow:hidden;margin-bottom:4px}
.sliderTrack{display:flex;transition:transform .35s ease;width:100%}
.pane{flex:0 0 100%;min-width:100%;padding:2px 14px 2px 2px}
.navArrow{position:absolute;top:46%;transform:translateY(-50%);z-index:5;width:34px;height:58px;border-radius:10px;background:rgba(255,255,255,.92);border:1px solid var(--line);font-size:26px;line-height:1;color:var(--txt);cursor:pointer;box-shadow:0 2px 10px rgba(0,0,0,.1)}
.navArrow:hover{background:#fff;color:var(--pri)}
.navArrow.left{left:-4px}.navArrow.right{right:6px}
.dots{text-align:center;margin:2px 0 14px}
.dot{display:inline-block;width:9px;height:9px;border-radius:50%;background:#cbd5e1;margin:0 5px;cursor:pointer;transition:all .2s}
.dot.on{background:var(--pri);width:22px;border-radius:5px}
#toast{position:fixed;top:60px;left:50%;transform:translateX(-50%);background:#1e293b;color:#fff;padding:8px 18px;border-radius:8px;z-index:9;opacity:.95}
#detailModal{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:8;display:flex;align-items:center;justify-content:center}
#detailModal.hidden{display:none}
@@ -79,15 +88,20 @@ tr:hover td{background:#f8fafc;cursor:pointer}
</div>
</div>
<div id="main" class="hidden">
<div class="cards" id="statCards"></div>
<div class="panel"><h3>近30天趋势</h3><div id="chTrend" style="height:300px"></div></div>
<div class="chartRow">
<div class="panel"><h3>评分级别分布</h3><div id="chLevel" style="height:280px"></div></div>
<div class="panel"><h3>学历分布</h3><div id="chEdu" style="height:280px"></div></div>
<div class="panel"><h3>期望城市 TOP8</h3><div id="chCity" style="height:280px"></div></div>
<div class="panel"><h3>筛选漏斗</h3><div id="chFunnel" style="height:280px"></div></div>
</div>
<div class="panel">
<div class="slider" id="slider">
<div class="sliderTrack" id="sliderTrack">
<section class="pane">
<div class="cards" id="statCards"></div>
<div class="panel"><h3>近30天趋势</h3><div id="chTrend" style="height:300px"></div></div>
<div class="chartRow">
<div class="panel"><h3>评分级别分布</h3><div id="chLevel" style="height:280px"></div></div>
<div class="panel"><h3>学历分布</h3><div id="chEdu" style="height:280px"></div></div>
<div class="panel"><h3>期望城市 TOP8</h3><div id="chCity" style="height:280px"></div></div>
<div class="panel"><h3>筛选漏斗</h3><div id="chFunnel" style="height:280px"></div></div>
</div>
</section>
<section class="pane">
<div class="panel">
<h3>候选人</h3>
<div class="filters">
<select id="q_level"><option value="">全部级别</option><option>推荐</option><option>待定</option><option>不推荐</option><option>不相关</option></select>
@@ -110,7 +124,13 @@ tr:hover td{background:#f8fafc;cursor:pointer}
<span id="pageNo">1</span>
<button class="btn sub small" onclick="page(1)">下一页</button>
</div>
</div>
</section>
</div>
<button class="navArrow left" onclick="slide(-1)">‹</button>
<button class="navArrow right" onclick="slide(1)">›</button>
</div>
<div class="dots"><span class="dot on" onclick="setPane(0)"></span><span class="dot" onclick="setPane(1)"></span></div>
<div class="panel hidden" id="userPanel"></div>
<div id="userModal" onclick="if(event.target===this)this.classList.add('hidden')" class="hidden">
<div class="panel" style="width:780px;max-width:94vw;max-height:88vh;overflow:auto">
@@ -134,6 +154,25 @@ tr:hover td{background:#f8fafc;cursor:pointer}
let me=null,pageCur=1,pageTotal=1;
const $=id=>document.getElementById(id);
const esc=s=>String(s??'').replace(/[&<>"]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]));
// ---------- 左右滑动双屏(0=看板 1=列表) ----------
let curPane=0;
function slide(d){setPane(curPane+d)}
function setPane(n){
n=Math.max(0,Math.min(1,n));curPane=n;
$('sliderTrack').style.transform=`translateX(-${n*100}%)`;
document.querySelectorAll('.dot').forEach((el,i)=>el.classList.toggle('on',i===n));
document.querySelector('.navArrow.left').style.visibility=n===0?'hidden':'visible';
document.querySelector('.navArrow.right').style.visibility=n===1?'hidden':'visible';
setTimeout(()=>charts.forEach(c=>c.resize()),400);
}
document.addEventListener('keydown',e=>{
if(!me||e.target.tagName==='INPUT'||e.target.tagName==='TEXTAREA')return;
if(e.key==='ArrowLeft')slide(-1);if(e.key==='ArrowRight')slide(1);
});
(()=>{let x0=null;const sl=$('slider');
sl.addEventListener('touchstart',e=>x0=e.touches[0].clientX,{passive:true});
sl.addEventListener('touchend',e=>{if(x0===null)return;const dx=e.changedTouches[0].clientX-x0;if(Math.abs(dx)>40)slide(dx<0?1:-1);x0=null},{passive:true});
})();
const tagCls={'推荐':'rec','待定':'maybe','不推荐':'no','不相关':'irr'};
function toast(t){const d=document.createElement('div');d.id='toast';d.textContent=t;document.body.appendChild(d);setTimeout(()=>d.remove(),1800)}
+4 -2
View File
@@ -45,8 +45,10 @@ const sleep = (ms) => new Promise(r => setTimeout(r, ms));
const canvasN = await p.evaluate(() => document.querySelectorAll('#main canvas').length);
ok(`图表已渲染(canvas=${canvasN},≥5)`, canvasN >= 5);
console.log('== 4. 候选人列表与筛选 ==');
await sleep(500);
console.log('== 4. 候选人列表与筛选(滑动到第二屏) ==');
await p.evaluate(() => setPane(1)); await sleep(500);
ok('滑到列表屏(箭头状态)', await p.evaluate(() => document.querySelector('.navArrow.left').style.visibility === 'visible'));
await sleep(300);
const rows1 = await p.evaluate(() => document.querySelectorAll('#tbody tr').length);
ok(`默认列表有数据(${rows1}行)`, rows1 > 0);
await p.selectOption('#q_level', '推荐');