app.js · 约 41932 字符
1/* ============================================================2 惠存会员 · 个体工商户门店会员储值系统 — 应用逻辑(jQuery 单页 SPA)3 ============================================================ */4(function(){5 "use strict";6 var LS_KEY = "hc_state_v1";78 /* ---------------- 状态(运行期持久化) ---------------- */9 function defaultState(){10 return {11 balance: 1280.00,12 gift: 360.00,13 points: 2480,14 signDays: [true,true,true,true,false,false,false],15 signedToday: false,16 coupons: JSON.parse(JSON.stringify(MY_COUPONS)),17 transactions: JSON.parse(JSON.stringify(TRANSACTIONS)),18 transfers: JSON.parse(JSON.stringify(TRANSFERS)),19 mallRedeemed: {},20 inviteCount: 321 };22 }23 function loadState(){24 try{ var s = JSON.parse(localStorage.getItem(LS_KEY)); if(s && typeof s.balance==="number") return s; }catch(e){}25 return defaultState();26 }27 function saveState(s){ try{ localStorage.setItem(LS_KEY, JSON.stringify(s)); }catch(e){} }28 var S = loadState();2930 /* ---------------- 工具 ---------------- */31 function money(n){ return "¥" + (Number(n)||0).toFixed(2); }32 function money0(n){ return "¥" + Math.round(Number(n)||0); }33 function discountText(d){ return d>=1 ? "无折扣" : (d*10).toFixed(1).replace(/\.0$/,"") + "折"; }34 function levelInfo(key){ for(var i=0;i<MEMBER_LEVELS.length;i++){ if(MEMBER_LEVELS[i].key===key) return MEMBER_LEVELS[i]; } return MEMBER_LEVELS[0]; }35 function nowStr(){ var d=new Date(); function p(n){return (n<10?"0":"")+n;} return d.getFullYear()+"-"+p(d.getMonth()+1)+"-"+p(d.getDate())+" "+p(d.getHours())+":"+p(d.getMinutes()); }36 function toast(msg){ var t=$("#toast"); t.text(msg).addClass("show"); clearTimeout(t[0]._t); t[0]._t=setTimeout(function(){ t.removeClass("show"); },1500); }37 function planById(id){ for(var i=0;i<RECHARGE_PLANS.length;i++){ if(RECHARGE_PLANS[i].id===id) return RECHARGE_PLANS[i]; } return null; }38 function mallById(id){ for(var i=0;i<MALL_ITEMS.length;i++){ if(MALL_ITEMS[i].id===id) return MALL_ITEMS[i]; } return null; }39 function poolById(id){ for(var i=0;i<COUPON_POOL.length;i++){ if(COUPON_POOL[i].id===id) return COUPON_POOL[i]; } return null; }40 function getParam(q,key){ if(!q) return ""; var p=q.split("&"); for(var i=0;i<p.length;i++){ var kv=p[i].split("="); if(kv[0]===key) return decodeURIComponent(kv[1]||""); } return ""; }41 function lv(key){ return levelInfo(key); }4243 /* ---------------- 顶部品牌栏 ---------------- */44 function topbar(){45 var ml = lv(MEMBER.level);46 return ''+47 '<div class="topbar">'+48 '<div class="brand">'+49 '<div class="logo">惠</div>'+50 '<div><div class="bname">'+STORE.name+'</div><div class="bsub">'+STORE.sub+'</div></div>'+51 '</div>'+52 '<div class="mini">'+53 '<div class="m"><div class="mk">储值本金</div><div class="mv">'+money0(S.balance)+'</div></div>'+54 '<div class="m"><div class="mk">赠送金</div><div class="mv">'+money0(S.gift)+'</div></div>'+55 '<div class="m"><div class="mk">积分</div><div class="mv">'+S.points+'</div></div>'+56 '</div>'+57 '</div>';58 }5960 /* ---------------- 底部 Tab ---------------- */61 var TABS = [62 {k:"home", t:"首页", i:"🏠"},63 {k:"recharge",t:"储值", i:"💰"},64 {k:"member", t:"会员", i:"👑"},65 {k:"mall", t:"商城", i:"🎁"},66 {k:"mine", t:"我的", i:"👤"}67 ];68 function tabbar(active){69 var h='';70 for(var i=0;i<TABS.length;i++){71 var t=TABS[i]; var on = (t.k===active)?" active":"";72 h+='<a class="'+on.trim()+'" data-to="#/'+t.k+'"><span class="ti">'+t.i+'</span>'+t.t+'</a>';73 }74 return h;75 }7677 /* ---------------- 子页头(带返回) ---------------- */78 function subbar(title){79 return '<div class="subbar"><span class="back" data-to="#/'+ (title==="我的"?"mine":(title==="储值中心"?"recharge":(title==="会员中心"?"member":(title==="积分商城"?"mall":"home")))) +'">‹ 返回</span><span class="t">'+title+'</span></div>';80 }8182 /* ============================================================83 视图:首页84 ============================================================ */85 function viewHome(){86 var ml = lv(MEMBER.level);87 var feats = "";88 for(var i=0;i<FEATURES.length;i++){ var f=FEATURES[i]; feats+='<div class="cell"><div class="gi">'+f.icon+'</div><div class="gt">'+f.title+'</div><div class="gp" style="color:#8a90a2;font-weight:500;font-size:10px;">'+f.desc+'</div></div>'; }89 var plans = "";90 for(var j=0;j<2;j++){ var p=RECHARGE_PLANS[j]; plans+=''+91 '<div class="plan '+(p.hot?"hot":"")+'">'+(p.tag?'<span class="tag">'+p.tag+'</span>':'')+92 '<div class="amt">'+money0(p.amount)+' <small>本金</small></div>'+93 '<div class="gift"><div class="g">赠 '+money0(p.gift)+'</div><div class="gt">+'+p.points+'分 · '+p.coupon.name+'</div></div>'+94 '</div>'; }95 var nts = "";96 for(var k=0;k<NOTICES.length;k++){ var n=NOTICES[k]; nts+='<div class="notice"><div class="nt"><div class="t">'+n.title+'</div><div class="x">'+n.text+'</div></div><div class="tm">'+n.time+'</div></div>'; }97 return topbar()+98 '<div class="banner"><div class="bage">🎉</div><div class="bt">会员日倒计时 '+MEMBER_DAY.countdownDays+' 天</div><div class="bs">'+STORE.memberDay+' 日全店积分翻倍 · 金卡以上再叠加折扣</div></div>'+99 '<div class="section"><h3><span class="bar"></span>快捷入口</h3>'+100 '<div class="quick">'+101 '<div class="q" data-to="#/recharge"><div class="qi">💰</div><div class="qt">储值</div></div>'+102 '<div class="q" data-to="#/mall"><div class="qi">🎁</div><div class="qt">积分商城</div></div>'+103 '<div class="q" data-to="#/coupons"><div class="qi">🎟️</div><div class="qt">我的券</div></div>'+104 '<div class="q" data-to="#/signin"><div class="qi">📅</div><div class="qt">签到</div></div>'+105 '</div>'+106 '</div>'+107 '<div class="section"><h3><span class="bar"></span>功能亮点<span class="more" data-to="#/member">会员中心 ›</span></h3><div class="grid">'+feats+'</div></div>'+108 '<div class="section"><h3><span class="bar"></span>储值推荐<span class="more" data-to="#/recharge">去储值 ›</span></h3>'+plans+'</div>'+109 '<div class="section"><h3><span class="bar"></span>消息通知</h3>'+nts+'</div>'+110 '<div style="height:8px"></div>';111 }112113 /* ============================================================114 视图:储值中心115 ============================================================ */116 function viewRecharge(){117 var ml = lv(MEMBER.level);118 var next = null; for(var i=0;i<MEMBER_LEVELS.length;i++){ if(MEMBER_LEVELS[i].key===MEMBER.level){ next = MEMBER_LEVELS[i+1]||null; break; } }119 var need = next ? Math.max(0, next.minSpend - MEMBER.totalSpend) : 0;120 var pct = next ? Math.min(100, Math.round(MEMBER.totalSpend/next.minSpend*100)) : 100;121 var plans="";122 for(var j=0;j<RECHARGE_PLANS.length;j++){ var p=RECHARGE_PLANS[j];123 plans+=''+124 '<div class="plan '+(p.hot?"hot":"")+'">'+(p.tag?'<span class="tag">'+p.tag+'</span>':'')+125 '<div class="amt">'+money0(p.amount)+' <small>本金</small></div>'+126 '<div class="gift"><div class="g">赠 '+money0(p.gift)+'</div><div class="gt">+'+p.points+'分 · '+p.coupon.name+'</div></div>'+127 '<div data-to="#/recharge/plan?plan='+p.id+'" style="margin-left:10px"><span class="btn sm blue">立即储值</span></div>'+128 '</div>';129 }130 return subbar("储值中心")+131 '<div class="hero"><div class="h1">我的储值余额</div>'+132 '<div style="font-size:30px;font-weight:800;margin-top:6px">'+money0(S.balance+S.gift)+'</div>'+133 '<div class="split" style="margin-top:10px">'+134 '<div class="box" style="background:rgba(255,255,255,.15)"><div class="n">'+money0(S.balance)+'</div><div class="l">本金(可提现)</div></div>'+135 '<div class="box" style="background:rgba(255,255,255,.15)"><div class="n">'+money0(S.gift)+'</div><div class="l">赠送金(营销)</div></div>'+136 '</div>'+137 '</div>'+138 (next?('<div class="section"><div class="row"><span class="k">升级进度('+ml.name+' → '+next.name+')</span><span class="v">'+pct+'%</span></div>'+139 '<div class="progress"><i style="width:'+pct+'%"></i></div>'+140 '<div class="muted">再消费 '+money0(need)+' 即可升级 '+next.name+',享 '+discountText(next.discount)+'</div></div>'):'')+141 '<div class="section"><h3><span class="bar"></span>储值套餐(阶梯赠送)</h3>'+plans+'</div>'+142 '<div class="section"><div class="row"><span class="k">储值专属折扣</span><span class="v">金卡 9 折 · 钻石 8.5 折</span></div>'+143 '<div class="row"><span class="k">赠送金规则</span><span class="v">本金/赠送金分账</span></div>'+144 '<div class="row"><span class="k">余额提醒</span><span class="v">不足自动推送</span></div>'+145 '<div class="row" data-to="#/recharge/record"><span class="k">储值 / 消费明细</span><span class="v" style="color:var(--blue)">查看 ›</span></div>'+146 '</div>'+147 '<div style="height:8px"></div>';148 }149150 /* ============================================================151 视图:储值下单152 ============================================================ */153 function viewPlan(q){154 var p = planById(getParam(q,"plan")) || RECHARGE_PLANS[1];155 return subbar("储值下单")+156 '<div class="section"><div class="plan hot" style="margin-bottom:0">'+(p.tag?'<span class="tag">'+p.tag+'</span>':'')+157 '<div class="amt">'+money0(p.amount)+' <small>本金</small></div>'+158 '<div class="gift"><div class="g">赠 '+money0(p.gift)+'</div><div class="gt">+'+p.points+'分</div></div></div>'+159 '<div class="row"><span class="k">到账本金</span><span class="v">'+money0(p.amount)+'</span></div>'+160 '<div class="row"><span class="k">赠送金</span><span class="v" style="color:var(--red)">'+money0(p.gift)+'</span></div>'+161 '<div class="row"><span class="k">赠送积分</span><span class="v">'+p.points+' 分</span></div>'+162 '<div class="row"><span class="k">赠送券</span><span class="v">'+p.coupon.name+'</span></div>'+163 '<div class="row"><span class="k">实付金额</span><span class="v" style="color:var(--red)">'+money0(p.amount)+'</span></div>'+164 '</div>'+165 '<div class="section"><h3><span class="bar"></span>支付方式</h3>'+166 '<div class="row"><span class="k">🟢 微信支付</span><span class="v">推荐</span></div>'+167 '<div class="row"><span class="k">🔵 支付宝</span><span class="v">可用</span></div>'+168 '<div class="row"><span class="k">💳 余额混合支付</span><span class="v">余额 + 差价</span></div>'+169 '</div>'+170 '<label class="section" style="display:flex;gap:8px;align-items:center;font-size:12px;color:var(--sub)"><input type="checkbox" checked> 我已阅读并同意《储值会员协议》</label>'+171 '<div class="fixedbar"><div class="btn blue" data-act="dopay" data-plan="'+p.id+'">确认支付 '+money0(p.amount)+'</div></div>'+172 '<div style="height:70px"></div>';173 }174175 /* ============================================================176 视图:储值 / 消费明细177 ============================================================ */178 function viewRecord(){179 var totalIn=0,totalOut=0;180 for(var i=0;i<S.transactions.length;i++){ var t=S.transactions[i]; if(t.type==="recharge") totalIn+=t.principal+t.gift; else totalOut+=t.principal; }181 var list="";182 for(var j=0;j<S.transactions.length;j++){ var t=S.transactions[j];183 var cls = t.type==="recharge"?"in":"out";184 var ic = t.type==="recharge"?"⬇️":"⬆️";185 var sign = t.type==="recharge"?"+":"-";186 list+='<div class="tx"><div class="ic '+cls+'">'+ic+'</div>'+187 '<div class="tt"><div class="t">'+t.title+'</div><div class="d">'+t.date+' · '+t.note+'</div></div>'+188 '<div class="am"><div class="'+cls+'">'+sign+money0(t.principal)+'</div>'+189 (t.gift>0?'<div class="sub">赠 '+money0(t.gift)+'</div>':'')+190 '<div class="sub">余 '+money0(t.balanceAfter)+'</div></div></div>';191 }192 return subbar("储值 / 消费明细")+193 '<div class="section"><div class="split">'+194 '<div class="box"><div class="n" style="color:var(--green)">'+money0(totalIn)+'</div><div class="l">累计储值(含赠)</div></div>'+195 '<div class="box"><div class="n" style="color:var(--navy)">'+money0(totalOut)+'</div><div class="l">累计消费</div></div>'+196 '</div></div>'+197 '<div class="section"><h3><span class="bar"></span>交易流水(本金 / 赠送金分列)</h3>'+list+'</div>'+198 '<div style="height:8px"></div>';199 }200201 /* ============================================================202 视图:会员中心203 ============================================================ */204 function viewMember(){205 var ml = lv(MEMBER.level);206 var next=null; for(var i=0;i<MEMBER_LEVELS.length;i++){ if(MEMBER_LEVELS[i].key===MEMBER.level){ next=MEMBER_LEVELS[i+1]||null; break; } }207 var need = next?Math.max(0,next.minSpend-MEMBER.totalSpend):0;208 var pct = next?Math.min(100,Math.round(MEMBER.totalSpend/next.minSpend*100)):100;209 var init = MEMBER.name.charAt(0);210 var权益=''+211 '<div class="grid">'+212 '<div class="cell" data-to="#/birthday"><div class="gi">🎂</div><div class="gt">生日礼</div></div>'+213 '<div class="cell" data-to="#/memberday"><div class="gi">🎉</div><div class="gt">会员日</div></div>'+214 '<div class="cell" data-to="#/recharge"><div class="gi">💰</div><div class="gt">储值专享</div></div>'+215 '<div class="cell" data-to="#/mine"><div class="gi">🛎️</div><div class="gt">专属客服</div></div>'+216 '</div>';217 return subbar("会员中心")+218 '<div class="lvlcard" style="background:linear-gradient(135deg,'+ml.color+','+ml.color+'cc)">'+219 '<div style="display:flex;align-items:center;gap:12px">'+220 '<div style="width:50px;height:50px;border-radius:50%;background:rgba(255,255,255,.25);display:flex;align-items:center;justify-content:center;font-size:24px;font-weight:800">'+init+'</div>'+221 '<div><div class="ln">'+MEMBER.name+'</div><div class="ld">'+MEMBER.phone+' · '+ml.name+'</div></div>'+222 '<div style="margin-left:auto" class="lvl" style="background:#fff;color:'+ml.color+'">'+discountText(ml.discount)+'</div>'+223 '</div>'+224 '<div class="lb"><span>生日 '+MEMBER.birthday+'</span><span>入会 '+MEMBER.joinedAt+'</span></div>'+225 '</div>'+226 (next?('<div class="section"><div class="row"><span class="k">升级进度('+ml.name+' → '+next.name+')</span><span class="v">'+pct+'%</span></div>'+227 '<div class="progress"><i style="width:'+pct+'%"></i></div>'+228 '<div class="muted">再消费 '+money0(need)+' 升级,享 '+discountText(next.discount)+' 与更多权益</div>'+229 '<div class="btn ghost sm" style="margin-top:10px" data-to="#/levels">查看等级权益</div></div>'):'')+230 '<div class="section"><h3><span class="bar"></span>我的权益</h3>'+权益+'</div>'+231 '<div style="height:8px"></div>';232 }233234 /* ============================================================235 视图:会员等级总览236 ============================================================ */237 function viewLevels(){238 var cards="";239 for(var i=0;i<MEMBER_LEVELS.length;i++){ var L=MEMBER_LEVELS[i];240 var b=""; for(var j=0;j<L.benefits.length;j++){ b+='<span>'+L.benefits[j]+'</span>'; }241 cards+='<div class="lvlcard" style="background:linear-gradient(135deg,'+L.color+','+L.color+'cc)">'+242 '<div class="ln">'+L.name+' · '+discountText(L.discount)+'</div>'+243 '<div class="ld">升级条件:累计消费满 '+money0(L.minSpend)+'</div>'+244 '<div class="lb">'+b+'</div></div>';245 }246 return subbar("会员等级")+247 '<div class="section"><h3><span class="bar"></span>4 档等级 · 折扣 0.1~9.9 折自定义</h3>'+cards+'</div>'+248 '<div class="section"><div class="row"><span class="k">自动升级</span><span class="v">累计消费 / 积分达标</span></div>'+249 '<div class="row"><span class="k">升级通知</span><span class="v">短信 + 微信推送</span></div>'+250 '<div class="row"><span class="k">权益生效</span><span class="v">即时同步</span></div></div>'+251 '<div style="height:8px"></div>';252 }253254 /* ============================================================255 视图:积分商城256 ============================================================ */257 function viewMall(){258 var cells="";259 for(var i=0;i<MALL_ITEMS.length;i++){ var g=MALL_ITEMS[i];260 cells+='<div class="cell" data-to="#/mall/detail?id='+g.id+'">'+261 '<div class="gi">'+g.icon+'</div><div class="gt">'+g.name+'</div>'+262 '<div class="gp">'+g.points+' 分</div>'+(g.hot?'<div class="tag" style="margin-top:2px">热</div>':'')+'</div>';263 }264 return subbar("积分商城")+265 '<div class="hero"><div class="h1">我的积分</div><div style="font-size:30px;font-weight:800;margin-top:4px">'+S.points+' 分</div>'+266 '<div class="h2">消费 1 元 = 1 分 · 签到 / 分享 / 储值均可赚分</div></div>'+267 '<div class="section"><h3><span class="bar"></span>积分商城<span class="more" data-to="#/coupons">我的券 ›</span></h3><div class="grid">'+cells+'</div></div>'+268 '<div class="section"><h3><span class="bar"></span>赚积分渠道</h3>'+269 '<div class="row"><span class="k">🛍️ 消费获分</span><span class="v">1 元 = 1 分</span></div>'+270 '<div class="row"><span class="k">💰 储值赠分</span><span class="v">大额额外送</span></div>'+271 '<div class="row"><span class="k">📅 每日签到</span><span class="v">最高 50 分</span></div>'+272 '<div class="row"><span class="k">🤝 老带新</span><span class="v">+200 分</span></div>'+273 '</div>'+274 '<div style="height:8px"></div>';275 }276277 /* ============================================================278 视图:积分商城详情 / 兑换279 ============================================================ */280 function viewMallDetail(q){281 var g = mallById(getParam(q,"id")) || MALL_ITEMS[0];282 return subbar("商品详情")+283 '<div class="section center">'+284 '<div style="font-size:60px">'+g.icon+'</div>'+285 '<div style="font-size:18px;font-weight:800;margin-top:6px">'+g.name+'</div>'+286 '<div class="tag" style="margin-top:6px">'+g.tag+'</div>'+287 '<div class="big gold" style="margin-top:10px">'+g.points+' 分</div>'+288 '<div class="muted">库存 '+g.stock+' 件 · 已兑 '+(S.mallRedeemed[g.id]||0)+' 件</div>'+289 '</div>'+290 '<div class="section"><h3><span class="bar"></span>兑换说明</h3>'+291 '<div class="row"><span class="k">所需积分</span><span class="v">'+g.points+' 分</span></div>'+292 '<div class="row"><span class="k">我的积分</span><span class="v">'+S.points+' 分</span></div>'+293 '<div class="row"><span class="k">兑换方式</span><span class="v">积分兑换 / 余额补差</span></div>'+294 '<div class="row"><span class="k">到账</span><span class="v">存入卡包</span></div>'+295 '</div>'+296 '<div class="fixedbar"><div class="btn '+(S.points>=g.points?"":"ghost")+'" data-act="exchange" data-id="'+g.id+'">'+(S.points>=g.points?("立即兑换 · "+g.points+" 分"):"积分不足")+'</div></div>'+297 '<div style="height:70px"></div>';298 }299300 /* ============================================================301 视图:我的优惠券 + 领券中心302 ============================================================ */303 function cpRow(c, actHtml){304 var leftTxt, leftCls="";305 if(c.type==="discount"){ leftTxt='<div class="v">'+(c.val/10).toFixed(1).replace(/\.0$/,"")+'</div><div class="vt">折</div>'; }306 else if(c.type==="times"){ leftTxt='<div class="v">×'+c.val+'</div><div class="vt">倍</div>'; leftCls="times"; }307 else { leftTxt='<div class="v">'+c.val+'</div><div class="vt">元</div>'; leftCls="dz"; }308 var cond = c.cond>0?("满"+c.cond+"可用"):"无门槛";309 return '<div class="cp '+leftCls+'"><div class="left">'+leftTxt+'</div>'+310 '<div class="right"><div class="cn">'+c.name+'</div><div class="cd">'+cond+'</div><div class="ce">有效期至 '+c.expire+'</div></div>'+311 (actHtml?'<div class="act">'+actHtml+'</div>':'')+'</div>';312 }313 function viewCoupons(){314 var list="";315 for(var i=0;i<S.coupons.length;i++){ var c=S.coupons[i];316 var act = c.status==="used"?'<span class="tag gray">已使用</span>':'<span class="btn sm" data-act="transfer" data-id="'+c.id+'">转赠</span>';317 list+=cpRow(c, act);318 }319 var pool="";320 for(var j=0;j<COUPON_POOL.length;j++){ var p=COUPON_POOL[j];321 pool+=cpRow(p, p.get?'<span class="btn sm blue" data-act="getcoupon" data-id="'+p.id+'">领取</span>':'<span class="tag gray">暂不可领</span>');322 }323 return subbar("我的优惠券")+324 '<div class="section"><h3><span class="bar"></span>我的券('+S.coupons.length+' 张)</h3>'+(list||'<div class="empty">暂无优惠券</div>')+'</div>'+325 '<div class="section"><h3><span class="bar"></span>领券中心</h3>'+pool+'</div>'+326 '<div style="height:8px"></div>';327 }328329 /* ============================================================330 视图:积分明细331 ============================================================ */332 function viewPoints(){333 // 由交易派生积分收支334 var logs=[];335 for(var i=0;i<S.transactions.length;i++){ var t=S.transactions[i];336 if(t.type==="recharge"){ logs.push({d:t.date, t:"储值赠分", v:"+"+planPointsOf(t), c:"green"}); }337 }338 // 签到积分339 var signed=0; for(var k=0;k<S.signDays.length;k++){ if(S.signDays[k]){ signed++; } }340 if(signed>0) logs.push({d:"近 7 日", t:"连续签到 ×"+signed, v:"+"+(signed*5)+" 分", c:"green"});341 var html="";342 for(var m=0;m<logs.length;m++){ html+='<div class="tx"><div class="ic in">⭐</div><div class="tt"><div class="t">'+logs[m].t+'</div><div class="d">'+logs[m].d+'</div></div><div class="am"><div class="in">'+logs[m].v+'</div></div></div>'; }343 return subbar("积分明细")+344 '<div class="hero"><div class="h1">当前积分</div><div style="font-size:30px;font-weight:800;margin-top:4px">'+S.points+' 分</div>'+345 '<div class="h2">100 积分 = 1 元 · 可抵现 / 兑礼 / 兑券</div></div>'+346 '<div class="section"><h3><span class="bar"></span>积分收支</h3>'+(html||'<div class="empty">暂无记录</div>')+'</div>'+347 '<div style="height:8px"></div>';348 }349 function planPointsOf(t){ // 粗略反推:本演示按本金估算赠分350 var p=planById("p2"); return Math.round(t.principal*1.2);351 }352353 /* ============================================================354 视图:签到355 ============================================================ */356 function viewSignin(){357 var cells="";358 for(var i=0;i<SIGNIN.days.length;i++){ var d=SIGNIN.days[i]; var on=S.signDays[i];359 cells+='<div class="s '+(on?"on":"")+'"><div class="sd">'+(on?"✓":("第"+d.day+"天"))+'</div><div class="sr">'+d.label+'</div></div>';360 }361 var signed=0; for(var k=0;k<S.signDays.length;k++){ if(S.signDays[k]) signed++; }362 return subbar("签到")+363 '<div class="section center"><div style="font-size:40px">📅</div><div style="font-size:17px;font-weight:800;margin-top:4px">连续签到 '+signed+' 天</div>'+364 '<div class="muted">每日签到领积分,第 7 天大奖 50 分</div></div>'+365 '<div class="section"><h3><span class="bar"></span>7 日签到</h3><div class="sign">'+cells+'</div>'+366 '<div style="margin-top:14px">'+(S.signedToday?'<div class="btn ghost">今日已签到 ✓</div>':'<div class="btn" data-act="signin">立即签到 +'+(SIGNIN.days[Math.min(signed,SIGNIN.days.length-1)].reward)+' 分</div>')+'</div>'+367 '</div>'+368 '<div style="height:8px"></div>';369 }370371 /* ============================================================372 视图:生日礼373 ============================================================ */374 function viewBirthday(){375 var items="";376 for(var i=0;i<BIRTHDAY.pack.length;i++){ var p=BIRTHDAY.pack[i];377 items+='<div class="row"><span class="k">🎁 '+p.name+'</span><span class="v"><span class="btn sm" data-act="claimbirthday" data-i="'+i+'">领取</span></span></div>';378 }379 return subbar("生日礼")+380 '<div class="banner" style="background:linear-gradient(135deg,#ffd1e8,#ff9ec7);color:#7a2a4d"><div class="bage">🎂</div><div class="bt">'+BIRTHDAY.greet+'</div><div class="bs">生日当月专享 · 情感化唤醒</div></div>'+381 '<div class="section"><h3><span class="bar"></span>生日礼包</h3>'+items+'</div>'+382 '<div class="section"><div class="row"><span class="k">生日月特权</span><span class="v">'+(BIRTHDAY.monthPrivilege?"已开启":"未开启")+'</span></div>'+383 '<div class="row"><span class="k">自动触达</span><span class="v">提前 3 天推送</span></div>'+384 '<div class="row"><span class="k">专属折扣</span><span class="v">生日当月双倍积分</span></div></div>'+385 '<div style="height:8px"></div>';386 }387388 /* ============================================================389 视图:会员日390 ============================================================ */391 function viewMemberDay(){392 var b="";393 for(var i=0;i<MEMBER_DAY.benefits.length;i++){ var x=MEMBER_DAY.benefits[i]; b+='<div class="row"><span class="k">'+x.icon+' '+x.text+'</span><span class="v">✓</span></div>'; }394 return subbar("会员日")+395 '<div class="hero"><div class="h1">会员日 · 每月 '+STORE.memberDay+' 日</div>'+396 '<div style="font-size:30px;font-weight:800;margin-top:4px">倒计时 '+MEMBER_DAY.countdownDays+' 天</div>'+397 '<div class="h2">锁定复购的黄金节点</div></div>'+398 '<div class="section"><h3><span class="bar"></span>当日权益</h3>'+b+'</div>'+399 '<div class="section"><div class="row"><span class="k">积分翻倍</span><span class="v">消费 ×2 积分</span></div>'+400 '<div class="row"><span class="k">专享折扣</span><span class="v">全单 9 折</span></div>'+401 '<div class="row"><span class="k">满赠</span><span class="v">满 100 赠礼</span></div></div>'+402 '<div class="fixedbar"><div class="btn blue" data-act="memberday">预约会员日提醒</div></div>'+403 '<div style="height:70px"></div>';404 }405406 /* ============================================================407 视图:老带新 / 推荐有礼408 ============================================================ */409 function viewInvite(){410 var list="";411 for(var i=0;i<INVITE.list.length;i++){ var x=INVITE.list[i];412 list+='<div class="row"><span class="k">'+x.name+' · '+x.phone+'</span><span class="v">'+x.status+'</span></div>'+413 '<div class="muted" style="margin:-6px 0 6px">奖励:'+x.reward+'</div>';414 }415 return subbar("老带新")+416 '<div class="banner"><div class="bage">🤝</div><div class="bt">'+INVITE.poster.title+'</div><div class="bs">'+INVITE.poster.sub+'</div></div>'+417 '<div class="section"><h3><span class="bar"></span>活动规则</h3><div class="muted">'+INVITE.rule+'</div></div>'+418 '<div class="section"><div class="row"><span class="k">我已成功邀请</span><span class="v">'+S.inviteCount+' 人</span></div></div>'+419 '<div class="section"><h3><span class="bar"></span>邀请记录</h3>'+list+'</div>'+420 '<div class="fixedbar"><div class="btn" data-act="invite">生成专属邀请海报</div></div>'+421 '<div style="height:70px"></div>';422 }423424 /* ============================================================425 视图:员工提成 / 排行榜(老板视角)426 ============================================================ */427 function viewStaff(){428 var rows="";429 var sorted = STAFF.slice().sort(function(a,b){ return b.commission-a.commission; });430 for(var i=0;i<sorted.length;i++){ var s=sorted[i];431 rows+='<div class="rank"><div class="no '+(i===0?"top":"")+'">'+(i+1)+'</div>'+432 '<div class="nm">'+s.name+'<div class="st">开卡 '+s.opened+' · 储值 '+money0(s.recharge)+' · 消费 '+money0(s.consume)+'</div></div>'+433 '<div class="cm">'+money0(s.commission)+'</div></div>';434 }435 return subbar("员工业绩")+436 '<div class="hero"><div class="h1">门店提成总览</div><div style="font-size:22px;font-weight:800;margin-top:4px">本月已发 '+(function(){var t=0;for(var i=0;i<STAFF.length;i++)t+=STAFF[i].commission;return money0(t);})()+'</div>'+437 '<div class="h2">'+STAFF_RULES+'</div></div>'+438 '<div class="section"><h3><span class="bar"></span>业绩排行榜</h3>'+rows+'</div>'+439 '<div class="section"><div class="row"><span class="k">我的身份</span><span class="v">店主(可提现)</span></div>'+440 '<div class="row"><span class="k">佣金到账</span><span class="v">微信零钱 T+1</span></div></div>'+441 '<div style="height:8px"></div>';442 }443444 /* ============================================================445 视图:礼品卡 / 转赠446 ============================================================ */447 function viewGiftCard(){448 var cards="";449 for(var i=0;i<GIFT_CARDS.length;i++){ var g=GIFT_CARDS[i];450 cards+='<div class="cell" style="text-align:left"><div style="font-size:30px">'+g.icon+'</div><div style="font-weight:800;margin-top:4px">'+g.name+'</div>'+451 '<div class="muted">售价 '+money0(g.price)+'</div><div class="btn sm blue" style="margin-top:6px" data-act="buygift" data-id="'+g.id+'">购买</div></div>';452 }453 var tr="";454 for(var j=0;j<S.transfers.length;j++){ var t=S.transfers[j];455 tr+='<div class="row"><span class="k">'+t.from+' → '+t.to+'</span><span class="v">'+t.item+'</span></div><div class="muted" style="margin:-6px 0 6px">'+t.date+'</div>';456 }457 return subbar("礼品卡")+458 '<div class="section"><h3><span class="bar"></span>礼品卡(赠好友)</h3><div class="grid">'+cards+'</div></div>'+459 '<div class="section"><h3><span class="bar"></span>转赠记录</h3>'+(tr||'<div class="empty">暂无转赠</div>')+'</div>'+460 '<div style="height:8px"></div>';461 }462463 /* ============================================================464 视图:经营数据看板(老板视角)465 ============================================================ */466 function viewDashboard(){467 var max=0; for(var i=0;i<DASHBOARD.rechargeTrend.length;i++){ if(DASHBOARD.rechargeTrend[i]>max) max=DASHBOARD.rechargeTrend[i]; }468 var bars="";469 for(var j=0;j<DASHBOARD.rechargeTrend.length;j++){470 var h=Math.round(DASHBOARD.rechargeTrend[j]/max*100);471 bars+='<div style="flex:1;text-align:center"><div style="height:80px;display:flex;align-items:flex-end;justify-content:center"><div style="width:60%;background:var(--gold-grad);border-radius:4px 4px 0 0;height:'+h+'%"></div></div><div class="muted" style="font-size:10px;margin-top:4px">'+DASHBOARD.trendDays[j]+'</div></div>';472 }473 var total=0; for(var k=0;k<DASHBOARD.memberLayers.length;k++) total+=DASHBOARD.memberLayers[k].count;474 var acc=0, conic="";475 for(var m=0;m<DASHBOARD.memberLayers.length;m++){ var pctv=Math.round(DASHBOARD.memberLayers[m].count/total*100); conic+=DASHBOARD.memberLayers[m].color+" "+(m===0?0:acc)+"% "+(acc+pctv)+"% "; acc+=pctv; }476 var legend="";477 for(var n=0;n<DASHBOARD.memberLayers.length;n++){ var L=DASHBOARD.memberLayers[n];478 legend+='<div class="row"><span class="k"><span style="display:inline-block;width:10px;height:10px;border-radius:3px;background:'+L.color+';margin-right:6px"></span>'+L.name+'</span><span class="v">'+L.count+' 人</span></div>';479 }480 return subbar("经营看板")+481 '<div class="section"><div class="donut">'+482 '<div class="d"><div class="big">'+DASHBOARD.totalMembers+'</div><div class="muted">会员总数</div></div>'+483 '<div class="d"><div class="big gold">'+money0(DASHBOARD.storedTotal)+'</div><div class="muted">储值总额</div></div>'+484 '</div><div class="donut" style="margin-top:10px">'+485 '<div class="d"><div class="big green">'+money0(DASHBOARD.todayRevenue)+'</div><div class="muted">今日营收</div></div>'+486 '<div class="d"><div class="big red">'+(DASHBOARD.repurchaseRate*100)+'%</div><div class="muted">复购率</div></div>'+487 '</div></div>'+488 '<div class="section"><h3><span class="bar"></span>近 7 日储值趋势</h3><div style="display:flex">'+bars+'</div></div>'+489 '<div class="section"><h3><span class="bar"></span>会员分层</h3>'+490 '<div style="display:flex;gap:14px;align-items:center">'+491 '<div style="width:110px;height:110px;border-radius:50%;background:conic-gradient('+conic+');position:relative"><div style="position:absolute;inset:22px;background:#fff;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--sub)">占比</div></div>'+492 '<div style="flex:1">'+legend+'</div>'+493 '</div></div>'+494 '<div class="section"><div class="row"><span class="k">数据导出</span><span class="v" style="color:var(--blue)">对账报表 ›</span></div>'+495 '<div class="row"><span class="k">实时同步</span><span class="v">多端一致</span></div></div>'+496 '<div style="height:8px"></div>';497 }498499 /* ============================================================500 视图:我的501 ============================================================ */502 function viewMine(){503 var ml = lv(MEMBER.level);504 var menu=[505 {i:"💰", t:"储值 / 消费明细", to:"#/recharge/record"},506 {i:"🎟️", t:"我的优惠券", to:"#/coupons"},507 {i:"⭐", t:"积分明细", to:"#/points"},508 {i:"📅", t:"每日签到", to:"#/signin"},509 {i:"🎂", t:"生日礼", to:"#/birthday"},510 {i:"🎉", t:"会员日", to:"#/memberday"},511 {i:"🤝", t:"老带新", to:"#/invite"},512 {i:"🎁", t:"礼品卡转赠", to:"#/giftcard"},513 {i:"📊", t:"经营数据看板", to:"#/dashboard"},514 {i:"🔔", t:"消息通知", to:"#/home"}515 ];516 var rows="";517 for(var i=0;i<menu.length;i++){ rows+='<div class="row" data-to="'+menu[i].to+'"><span class="k">'+menu[i].i+' '+menu[i].t+'</span><span class="v" style="color:var(--blue)">›</span></div>'; }518 return subbar("我的")+519 '<div class="lvlcard" style="background:linear-gradient(135deg,'+ml.color+','+ml.color+'cc)">'+520 '<div style="display:flex;align-items:center;gap:12px">'+521 '<div style="width:50px;height:50px;border-radius:50%;background:rgba(255,255,255,.25);display:flex;align-items:center;justify-content:center;font-size:22px;font-weight:800">'+MEMBER.name.charAt(0)+'</div>'+522 '<div><div class="ln">'+MEMBER.name+'</div><div class="ld">'+MEMBER.phone+' · '+ml.name+'('+discountText(ml.discount)+')</div></div>'+523 '</div>'+524 '<div class="split" style="margin-top:12px">'+525 '<div class="box" style="background:rgba(255,255,255,.15)"><div class="n">'+money0(S.balance)+'</div><div class="l">本金</div></div>'+526 '<div class="box" style="background:rgba(255,255,255,.15)"><div class="n">'+money0(S.gift)+'</div><div class="l">赠送金</div></div>'+527 '<div class="box" style="background:rgba(255,255,255,.15)"><div class="n">'+S.points+'</div><div class="l">积分</div></div>'+528 '</div>'+529 '</div>'+530 '<div class="section">'+rows+'</div>'+531 '<div class="section center"><div class="muted">'+STORE.name+' · '+STORE.address+'</div><div class="muted">客服 '+STORE.phone+'</div></div>'+532 '<div style="height:8px"></div>';533 }534535 /* ============================================================536 视图:会员支付折扣演示537 ============================================================ */538 function viewPay(){539 var ml = lv(MEMBER.level);540 var origin=88; var disc=+(origin*ml.discount).toFixed(2);541 return subbar("扫码支付")+542 '<div class="section center"><div style="font-size:40px">💳</div><div class="muted">会员支付自动识别折扣</div>'+543 '<div style="font-size:14px;margin-top:8px">原价 <s>'+money(origin)+'</s></div>'+544 '<div class="big red" style="font-size:34px">'+money(disc)+'</div>'+545 '<div class="tag">'+ml.name+' · '+discountText(ml.discount)+'</div></div>'+546 '<div class="section"><h3><span class="bar"></span>支付明细</h3>'+547 '<div class="row"><span class="k">商品金额</span><span class="v">'+money(origin)+'</span></div>'+548 '<div class="row"><span class="k">会员折扣</span><span class="v" style="color:var(--red)">-'+money((origin-disc).toFixed(2))+'</span></div>'+549 '<div class="row"><span class="k">可用券</span><span class="v">15 元满 50 券</span></div>'+550 '<div class="row"><span class="k">余额抵扣</span><span class="v">'+money0(Math.min(S.balance+S.gift, disc-15))+'</span></div>'+551 '<div class="row"><span class="k">实付</span><span class="v" style="color:var(--red)">'+money(Math.max(0,(disc-15)-(S.balance+S.gift>0?0:0)))+'</span></div>'+552 '</div>'+553 '<div class="section"><div class="row"><span class="k">支付方式</span><span class="v">微信 / 支付宝 / 余额</span></div>'+554 '<div class="row"><span class="k">积分到账</span><span class="v">+'+(Math.round(disc))+' 分</span></div></div>'+555 '<div class="fixedbar"><div class="btn blue" data-act="pay">确认支付 '+money(Math.max(0.01, disc-15))+'</div></div>'+556 '<div style="height:70px"></div>';557 }558559 /* ============================================================560 路由表561 ============================================================ */562 var ROUTES = {563 "home": viewHome,564 "recharge": viewRecharge,565 "recharge/plan": viewPlan,566 "recharge/record": viewRecord,567 "member": viewMember,568 "levels": viewLevels,569 "mall": viewMall,570 "mall/detail": viewMallDetail,571 "coupons": viewCoupons,572 "points": viewPoints,573 "signin": viewSignin,574 "birthday": viewBirthday,575 "memberday": viewMemberDay,576 "invite": viewInvite,577 "staff": viewStaff,578 "giftcard": viewGiftCard,579 "dashboard": viewDashboard,580 "mine": viewMine,581 "pay": viewPay582 };583584 /* ---------------- 渲染 ---------------- */585 function fullRoute(){586 var h = location.hash.replace(/^#\//,"");587 if(!h) return "home";588 return h;589 }590 function render(){591 var full = fullRoute();592 var q = "";593 if(full.indexOf("?")>=0){ q = full.split("?")[1]; full = full.split("?")[0]; }594 var base = full.split("/")[0];595 var fn = ROUTES[full] || viewHome;596 $("#app").html(fn(q));597 var tabBase = (base==="recharge"||base==="member"||base==="mall"||base==="mine")?base:"home";598 $("#tabbar").html(tabbar(tabBase));599 window.scrollTo(0,0);600 }601602 /* ---------------- 全局点击 ---------------- */603 $(document).on("click","[data-to]", function(e){604 e.preventDefault();605 var to = $(this).attr("data-to");606 if(to) location.hash = to;607 });608 $(document).on("click","[data-act]", function(){609 var act = $(this).attr("data-act");610 if(act==="dopay"){611 var p = planById($(this).attr("data-plan")) || RECHARGE_PLANS[1];612 S.balance += p.amount; S.gift += p.gift; S.points += p.points;613 S.transactions.unshift({ id:Date.now(), type:"recharge", title:"储值充值", date:nowStr(), principal:p.amount, gift:p.gift, balanceAfter:S.balance+S.gift, note:"充 "+p.amount+" 送 "+p.gift });614 if(p.coupon){ S.coupons.push({ id:"m"+Date.now(), name:p.coupon.name, type:"fullcut", val:p.coupon.val, cond:(p.coupon.val>=15?50:0), expire:"2026-12-31", status:"unused" }); }615 saveState(S); toast("储值成功,赠送金已到账"); location.hash="#/recharge";616 }617 else if(act==="signin"){618 if(S.signedToday){ toast("今日已签到"); return; }619 var idx=0; for(var i=0;i<S.signDays.length;i++){ if(!S.signDays[i]){ idx=i; break; } if(i===S.signDays.length-1) idx=i; }620 S.signDays[idx]=true; var rw=SIGNIN.days[idx].reward; S.points+=rw; S.signedToday=true; saveState(S); toast("签到成功 +"+rw+" 分"); render();621 }622 else if(act==="getcoupon"){623 var c=poolById($(this).attr("data-id")); if(!c) return;624 S.coupons.push({ id:"m"+Date.now(), name:c.name, type:c.type, val:c.val, cond:c.cond, expire:c.expire, status:"unused" });625 saveState(S); toast("领取成功,已存入卡包"); render();626 }627 else if(act==="exchange"){628 var g=mallById($(this).attr("data-id")); if(!g) return;629 if(S.points<g.points){ toast("积分不足,去赚分吧"); return; }630 S.points-=g.points; S.mallRedeemed[g.id]=(S.mallRedeemed[g.id]||0)+1; saveState(S); toast("兑换成功,已存入卡包"); location.hash="#/coupons";631 }632 else if(act==="transfer"){ toast("转赠链接已生成,可分享给好友"); }633 else if(act==="claimbirthday"){ toast("生日礼包已领取 🎂"); }634 else if(act==="memberday"){ toast("已预约会员日提醒 🔔"); }635 else if(act==="invite"){ toast("专属邀请海报已生成,可分享"); }636 else if(act==="buygift"){ toast("礼品卡购买链接已生成 🎁"); }637 else if(act==="pay"){ toast("支付成功,积分已到账 🎉"); }638 });639640 /* ---------------- 启动 ---------------- */641 $(window).on("hashchange", render);642 $(function(){ if(!location.hash) location.hash="#/home"; render(); });643})();644