app.js · 约 11747 字符
1$(function () {
2 var CATS = [
3 {id:'all', name:'全部'},
4 {id:'milk', name:'招牌奶茶'},
5 {id:'fruit', name:'鲜果茶'},
6 {id:'coffee', name:'咖啡'},
7 {id:'pure', name:'纯茶'}
8 ];
9 var DRINKS = [
10 {id:'d1', name:'招牌珍珠奶茶', cat:'milk', icon:'🧋', price:12, desc:'经典红茶底 + Q弹黑糖珍珠', tag:'热销'},
11 {id:'d2', name:'芋泥啵啵奶茶', cat:'milk', icon:'🧋', price:16, desc:'绵密芋泥搭配啵啵脆波波', tag:'新品'},
12 {id:'d3', name:'芝芝莓莓', cat:'fruit', icon:'🍓', price:18, desc:'新鲜草莓 + 海盐芝士奶盖', tag:'人气'},
13 {id:'d4', name:'满杯红柚', cat:'fruit', icon:'🍊', price:17, desc:'西柚果肉 + 高山绿茶', tag:''},
14 {id:'d5', name:'多肉葡萄', cat:'fruit', icon:'🍇', price:19, desc:'整颗去皮葡萄 + 茉莉绿', tag:'热销'},
15 {id:'d6', name:'生椰拿铁', cat:'coffee', icon:'☕', price:18, desc:'椰乳 + 意式浓缩咖啡', tag:'新品'},
16 {id:'d7', name:'美式咖啡', cat:'coffee', icon:'☕', price:13, desc:'清爽不苦,唤醒下午', tag:''},
17 {id:'d8', name:'茉莉初雪', cat:'pure', icon:'🍵', price:10, desc:'茉莉绿茶,清雅回甘', tag:''},
18 {id:'d9', name:'高山乌龙', cat:'pure', icon:'🍵', price:11, desc:'炭焙乌龙,醇厚耐泡', tag:''}
19 ];
20 var DMAP = {}; DRINKS.forEach(function (d) { DMAP[d.id] = d; });
21 var CART = load('tea_cart', {});
22 var ORDERS = load('tea_orders', []);
23
24 function load(k, def) { try { return JSON.parse(localStorage.getItem(k)) || def; } catch (e) { return def; } }
25 function save(k, v) { localStorage.setItem(k, JSON.stringify(v)); }
26 function money(n) { return '¥' + n; }
27 function toast(msg) { var t = $('#toast'); t.text(msg).addClass('show'); setTimeout(function () { t.removeClass('show'); }, 1400); }
28 function cartCount() { var n = 0; for (var k in CART) n += CART[k]; return n; }
29 function cartTotal() { var s = 0; for (var k in CART) s += CART[k] * DMAP[k].price; return s; }
30 function syncBadge() {
31 var n = cartCount(); var b = $('#cartBadge');
32 if (n > 0) { b.text(n).addClass('show'); } else { b.removeClass('show').text(''); }
33 }
34 function addCart(id) {
35 CART[id] = (CART[id] || 0) + 1; save('tea_cart', CART); syncBadge();
36 var d = DMAP[id]; toast('已加入购物车 · ' + d.name);
37 }
38 function setQty(id, q) {
39 if (q <= 0) { delete CART[id]; } else { CART[id] = q; }
40 save('tea_cart', CART); syncBadge(); renderCart();
41 }
42
43 function renderHome() {
44 var quick = CATS.slice(1).map(function (c) {
45 var ic = {milk:'🧋', fruit:'🍓', coffee:'☕', pure:'🍵'}[c.id];
46 return '<a class="quick" data-cat="' + c.id + '"><span class="qi">' + ic + '</span>' + c.name + '</a>';
47 }).join('');
48 var rec = DRINKS.slice(0, 4).map(function (d) {
49 return '<div class="good"><div class="pic">' + (d.tag ? '<span class="tag">' + d.tag + '</span>' : '') + d.icon + '</div>' +
50 '<div class="info"><div class="gn">' + d.name + '</div><div class="gd">' + d.desc + '</div>' +
51 '<div class="row"><span class="price"><b>¥</b>' + d.price + '</span>' +
52 '<button class="add" data-add="' + d.id + '">+</button></div></div></div>';
53 }).join('');
54 $('#view').html(
55 '<div class="banner"><h2>今日鲜萃 🍃</h2><p>会员下单满 20 元减 3 元,新客首杯 8 折</p><span class="leaf">🍃</span></div>' +
56 '<div class="sec-t">快速点单 <small>挑你喜欢的</small></div>' +
57 '<div class="quick">' + quick + '</div>' +
58 '<div class="sec-t" style="margin-top:16px">招牌推荐 <small>人气饮品</small></div>' +
59 '<div class="grid">' + rec + '</div>'
60 );
61 $('#view').find('[data-cat]').on('click', function () { location.hash = '#/menu'; setTimeout(function(){ gotoCat($(this).data('cat')); }, 30); });
62 $('#view').find('[data-add]').on('click', function () { addCart($(this).data('add')); });
63 }
64
65 var curCat = 'all';
66 function gotoCat(cat) {
67 curCat = cat;
68 $('.cats').find('.cat').removeClass('on');
69 $('.cats').find('.cat[data-c="' + cat + '"]').addClass('on');
70 renderMenuList();
71 }
72 function renderMenu() {
73 var side = CATS.map(function (c) {
74 return '<div class="cat ' + (c.id === curCat ? 'on' : '') + '" data-c="' + c.id + '">' + c.name + '</div>';
75 }).join('');
76 $('#view').html('<div class="sec-t">点单 <small>选好喝的一杯</small></div><div class="menu"><div class="cats">' + side + '</div><div class="mlist" id="mlist"></div></div>');
77 $('.cats').find('.cat').on('click', function () { gotoCat($(this).data('c')); });
78 renderMenuList();
79 }
80 function renderMenuList() {
81 var list = DRINKS.filter(function (d) { return curCat === 'all' || d.cat === curCat; });
82 var html = list.map(function (d) {
83 return '<div class="item"><div class="ip">' + d.icon + '</div><div class="it">' +
84 '<div class="in">' + d.name + (d.tag ? ' <span style="color:#ef4444;font-size:11px">·' + d.tag + '</span>' : '') + '</div>' +
85 '<div class="ides">' + d.desc + '</div>' +
86 '<div class="ir"><span class="price"><b>¥</b>' + d.price + '</span>' +
87 '<button class="add" data-add="' + d.id + '">+</button></div></div></div>';
88 }).join('');
89 $('#mlist').html(html);
90 $('#mlist').find('[data-add]').on('click', function () { addCart($(this).data('add')); });
91 }
92
93 function renderCart() {
94 var keys = Object.keys(CART);
95 if (!keys.length) {
96 $('#view').html('<div class="empty"><span class="big">🛒</span>购物车还是空的<br>去点单挑一杯吧~</div>');
97 $('.totalbar').hide(); return;
98 }
99 var items = keys.map(function (k) {
100 var d = DMAP[k];
101 return '<div class="ci"><div class="cp">' + d.icon + '</div><div class="cm">' +
102 '<div class="cn">' + d.name + '</div><div class="cp2">¥' + d.price + '</div></div>' +
103 '<div class="stepper"><button data-dec="' + k + '">−</button><span>' + CART[k] + '</span>' +
104 '<button data-inc="' + k + '">+</button></div></div>';
105 }).join('');
106 $('#view').html('<div class="sec-t">购物车 <small>' + keys.length + ' 种饮品</small></div>' + items);
107 $('#view').find('[data-inc]').on('click', function () { setQty($(this).data('inc'), CART[$(this).data('inc')] + 1); });
108 $('#view').find('[data-dec]').on('click', function () { setQty($(this).data('dec'), CART[$(this).data('dec')] - 1); });
109 var total = cartTotal();
110 if (!$('.totalbar').length) {
111 $('body').append('<div class="totalbar"><span class="t">合计</span><span class="amt">' + money(total) + '</span><button class="btn btn-go" id="goPay">去结算</button></div>');
112 } else { $('.totalbar').show(); $('.totalbar .amt').text(money(total)); }
113 $('#goPay').off('click').on('click', openCheckout);
114 }
115
116 function openCheckout() {
117 var total = cartTotal();
118 var listHtml = Object.keys(CART).map(function (k) {
119 return '<div class="ckrow"><span>' + DMAP[k].name + ' ×' + CART[k] + '</span><b>' + money(DMAP[k].price * CART[k]) + '</b></div>';
120 }).join('');
121 var html = '<div class="mask show" id="mask"><div class="sheet"><h3>确认订单</h3>' +
122 '<div class="field"><label>取餐方式</label><input value="到店自取 · 茶语时光(中心店)" readonly></div>' +
123 '<div class="field"><label>手机号</label><input id="cktel" value="138****6688"></div>' +
124 '<div class="field"><label>备注</label><textarea id="cknote" rows="2" placeholder="如:少糖、去冰、加珍珠"></textarea></div>' +
125 '<div style="background:#f8fafc;border-radius:12px;padding:10px;margin-bottom:12px">' + listHtml +
126 '<div class="ckrow" style="border-top:1px dashed #e2e8f0;margin-top:6px;padding-top:8px"><span>合计</span><b style="color:#ef4444">' + money(total) + '</b></div></div>' +
127 '<button class="btn-block" id="submitOrder">提交订单 · ' + money(total) + '</button>' +
128 '<button class="btn-block" style="background:#e2e8f0;color:#475569;margin-top:8px" id="closeSheet">取消</button>' +
129 '</div></div>';
130 $('#mask').remove();
131 $('body').append(html);
132 $('#closeSheet').on('click', function () { $('#mask').remove(); });
133 $('#submitOrder').on('click', function () {
134 var no = 'CY' + Date.now().toString().slice(-8);
135 var items = Object.keys(CART).map(function (k) { return {name: DMAP[k].name, qty: CART[k], price: DMAP[k].price}; });
136 ORDERS.unshift({ no: no, time: fmtNow(), total: total, status: '制作中', items: items });
137 save('tea_orders', ORDERS);
138 CART = {}; save('tea_cart', CART); syncBadge();
139 $('#mask').remove(); $('.totalbar').remove();
140 toast('下单成功 · ' + no);
141 location.hash = '#/mine';
142 });
143 }
144 function fmtNow() {
145 var d = new Date();
146 function p(n) { return n < 10 ? '0' + n : n; }
147 return d.getFullYear() + '-' + p(d.getMonth() + 1) + '-' + p(d.getDate()) + ' ' + p(d.getHours()) + ':' + p(d.getMinutes());
148 }
149
150 function renderMine() {
151 var html = '<div class="profile"><div class="av">🧑🍳</div><div><div class="pn">茶语会员</div>' +
152 '<div class="ps">累计消费 ¥' + totalSpent() + ' · 等级 Lv.3</div></div></div>';
153 if (!ORDERS.length) {
154 html += '<div class="empty"><span class="big">🧾</span>还没有订单<br>去点一杯喜欢的饮品吧~</div>';
155 } else {
156 html += '<div class="ostat">我的订单(' + ORDERS.length + ')</div>';
157 html += ORDERS.map(function (o) {
158 var names = o.items.map(function (i) { return i.name + '×' + i.qty; }).join('、');
159 return '<div class="order"><div class="oh"><span>订单号 ' + o.no + '</span><span>' + o.time + '</span></div>' +
160 '<div class="ob">' + names + '</div>' +
161 '<div class="of"><span class="price"><b>¥</b>' + o.total + '</span><span class="obadge">' + o.status + '</span></div></div>';
162 }).join('');
163 }
164 $('#view').html(html);
165 }
166 function totalSpent() {
167 var s = 0; ORDERS.forEach(function (o) { s += o.total; }); return s;
168 }
169
170 function router() {
171 var h = location.hash || '#/home';
172 var route = h.replace('#/', '').split('/')[0];
173 $('.tab').removeClass('active');
174 var map = {home:'#/home', menu:'#/menu', cart:'#/cart', mine:'#/mine'};
175 $('.tab[data-go="' + (map[route] || '#/home') + '"]').addClass('active');
176 if (route === 'menu') renderMenu();
177 else if (route === 'cart') renderCart();
178 else if (route === 'mine') renderMine();
179 else renderHome();
180 $('#view').scrollTop(0);
181 window.scrollTo(0, 0);
182 }
183
184 // 底部 Tab 点击
185 $('.tab').on('click', function (e) { e.preventDefault(); location.hash = $(this).data('go'); });
186 $(window).on('hashchange', router);
187
188 // 预置示例数据(首次进入且为空时),保证演示完整
189 if (!localStorage.getItem('tea_seed')) {
190 if (Object.keys(CART).length === 0) { CART = {d1:1, d5:2}; save('tea_cart', CART); }
191 if (ORDERS.length === 0) {
192 ORDERS = [
193 {no:'CY08261301', time:'2026-08-26 15:20', total:41, status:'已完成', items:[{name:'招牌珍珠奶茶',qty:1,price:12},{name:'多肉葡萄',qty:2,price:19},{name:'生椰拿铁',qty:1,price:18}]},
194 {no:'CY08251284', time:'2026-08-25 10:08', total:29, status:'已完成', items:[{name:'芝芝莓莓',qty:1,price:18},{name:'满杯红柚',qty:1,price:17}]}
195 ];
196 save('tea_orders', ORDERS);
197 }
198 localStorage.setItem('tea_seed', '1');
199 }
200 syncBadge();
201 if (!location.hash) location.hash = '#/home';
202 router();
203});
204