首页/ mobileweb/ 茶语时光 · 饮品点单 H5/ 代码预览

💻 代码预览 · 茶语时光 · 饮品点单 H5

mw_food · 上传者 驰旭教育
← 返回详情
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