小草K歌_H5/app.js · 约 5902 字符
1// 小草K歌 · 逻辑层
2const $=s=>document.querySelector(s), $$=s=>document.querySelectorAll(s);
3const store={
4 get queue(){return JSON.parse(localStorage.getItem('kt_queue')||'[]')},
5 set queue(v){localStorage.setItem('kt_queue',JSON.stringify(v))},
6 get orders(){return JSON.parse(localStorage.getItem('kt_orders')||'[]')},
7 set orders(v){localStorage.setItem('kt_orders',JSON.stringify(v))},
8 get coupons(){return JSON.parse(localStorage.getItem('kt_coupons')||JSON.stringify(COUPONS))},
9 set coupons(v){localStorage.setItem('kt_coupons',JSON.stringify(v))}
10};
11function fmt(n){return '¥'+n.toFixed(0)}
12function toast(msg){const t=document.createElement('div');t.textContent=msg;t.style.cssText='position:fixed;top:20%;left:50%;transform:translateX(-50%);background:rgba(0,0,0,.85);color:#fff;padding:10px 20px;border-radius:20px;font-size:13px;z-index:999;transition:opacity .3s';document.body.appendChild(t);setTimeout(()=>{t.style.opacity='0';setTimeout(()=>t.remove(),300)},1200)}
13/* 点歌 */
14function addSong(id){
15 const s=SONGS.find(x=>x.id==id);if(!s)return;
16 const q=store.queue;
17 if(q.find(i=>i.id===id)){toast('「'+s.name+'」已在歌单');return}
18 q.push(s);store.queue=q;
19 toast('已点歌:'+s.name);
20 refreshPlaying();
21}
22function refreshPlaying(){
23 const bar=$('#playing-bar');
24 if(bar){
25 const q=store.queue;
26 bar.style.display=q.length?'flex':'none';
27 $('#pb-song').textContent=q.length?q[0].name+' - '+q[0].singer:'';
28 $('#pb-count').textContent='已点 '+q.length+' 首';
29 }
30}
31function renderSongs(){
32 const q=store.queue;
33 $('#song-list').innerHTML=SONGS.map(s=>`
34 <div class="song-row">
35 <span class="sr-rank">${s.rank<4?'🔥':''}${s.rank}</span>
36 <div style="flex:1"><div class="sr-name">${s.name}</div><div class="sr-singer">${s.singer} · ${s.cat}</div></div>
37 <span class="sr-add" onclick="addSong(${s.id})">点歌</span>
38 </div>`).join('');
39 $('#queue-list').innerHTML=q.length?q.map(s=>`
40 <div class="song-row"><span class="sr-rank">🎵</span>
41 <div style="flex:1"><div class="sr-name">${s.name}</div><div class="sr-singer">${s.singer}</div></div>
42 <span class="sr-add" onclick="const q=store.queue;store.queue=q.filter(i=>i.id!==${s.id});renderSongs();refreshPlaying()">删除</span></div>`).join(''):'<div class="empty">歌单还是空的<br>点几首热歌开嗓吧~</div>';
43}
44/* 包厢 */
45let BK={room:null,slot:0};
46function renderRooms(){
47 $('#room-grid').innerHTML=ROOMS.map((r,i)=>`
48 <div class="room-item">
49 <span class="badge ${r.tag==='hot'?'badge-hot':r.tag==='new'?'badge-new':''} ri-tag">${r.tag==='hot'?'热门':r.tag==='new'?'新装':''}</span>
50 <div class="ri-emoji">${r.emoji}</div>
51 <div class="ri-name">${r.name}</div>
52 <div class="ri-meta">${r.seats} · ${r.desc}</div>
53 <div class="ri-price">¥${r.price}<small style="font-size:10px;color:#6f67a0">/${r.unit}</small></div>
54 </div>`).join('');
55 $('#time-tabs').innerHTML=TIME_SLOTS.map((t,i)=>'<span class="time-tab'+(i===0?' sel':'')+'" onclick="BK.slot='+i+';$$('.time-tab').forEach(x=>x.classList.remove('sel'));this.classList.add('sel')">'+t.name+' '+t.time+' <b style="color:var(--gold)">'+t.discount+'</b></span>').join('');
56}
57function submitRoom(){
58 if(BK.room===null){toast('请选择包厢房型');return}
59 const r=ROOMS[BK.room];const t=TIME_SLOTS[BK.slot];
60 const deposit=Math.round(r.price*2*0.3);
61 const o={id:'KT'+Date.now().toString().slice(-8),room:r.name,emoji:r.emoji,slot:t.name+'('+t.time+')',price:r.price*2,deposit,status:'待开房',time:new Date().toLocaleString('zh-CN',{month:'numeric',day:'numeric',hour:'2-digit',minute:'2-digit'})};
62 store.orders=[o,...store.orders];store.coupons=store.coupons.slice(1);
63 toast('包厢预订成功,定金 '+fmt(deposit)+' 元');
64 setTimeout(()=>location.href='order.html',800);
65}
66function renderOrders(){
67 const wrap=$('#order-list');const orders=store.orders;
68 const steps=[['待开房','✓'],['已开房','🎤'],['欢唱中','🎶'],['已结账','💳']];
69 if(!orders.length){wrap.innerHTML='<div class="empty"><span class="e-icon">🎤</span>还没有订单<br>开个包厢high起来~</div>';return}
70 wrap.innerHTML=orders.map(o=>`
71 <div class="order-card">
72 <div class="oc-head"><span>${o.time} · 订单号 ${o.id}</span><span class="oc-status">● ${o.status}</span></div>
73 <div class="oc-body"><span class="oc-emoji">${o.emoji}</span>
74 <div><div class="oc-name">${o.room} · ${o.slot}</div><div class="oc-meta">已付定金 ¥${o.deposit} · 到店核销开房</div></div>
75 <div class="oc-price">¥${o.price}</div>
76 </div>
77 <div class="oc-steps" style="display:flex;justify-content:space-between;margin-top:12px">${steps.map((s,i)=>'<div style="text-align:center;font-size:10px;color:#8b83b5;flex:1"><div style="width:20px;height:20px;border-radius:50%;background:'+(i<=0?'linear-gradient(135deg,#7c3aed,#22d3ee)':'#2a2350')+';margin:0 auto 3px;display:flex;align-items:center;justify-content:center;font-size:11px;color:#fff">'+s[1]+'</div>'+s[0]+'</div>').join('')}</div>
78 </div>`).join('');
79 $('#timer-card').innerHTML='<div class="tc-time">02:35</div><div class="tc-body"><b>欢唱剩余时间</b><br>房间:豪华房 A08 · 已欢唱 1小时25分<br>可在线加时 / 续订酒水</div><button class="btn btn-primary" style="width:auto;padding:8px 16px;font-size:12px" onclick="toast('已发送加时申请,店员正在处理')">加时</button>';
80}
81function renderMine(){
82 $('#u-name').textContent=USER.name;$('#u-level').textContent=USER.level+' · 累计欢唱 '+USER.times+' 次';
83 $('#m-points').textContent=USER.points;$('#m-balance').textContent=USER.balance;
84 $('#m-coupons').textContent=USER.coupons+store.coupons.length;
85 $('#m-times').textContent=USER.times;
86}
87