r117/public/admin.js · 约 23508 字符
1/* 甜趣蛋糕 · 商家后台逻辑(PHP 后端 admin API;只读开关在 config.php 中控制) */2const AD = (function () {3 'use strict';4 let RO = false; // 只读5 let navs = [6 ['dashboard', '📊 看板'], ['products', '🍰 商品'], ['orders', '📦 订单'],7 ['members', '👥 会员'], ['coupons', '🎟️ 优惠券'], ['reviews', '⭐ 评价'],8 ['banners', '🖼️ 轮播'], ['custom', '🎨 定制'], ['settings', '⚙️ 设置']9 ];10 let cur = 'dashboard';1112 function $(s) { return document.querySelector(s); }13 function toast(m) { const t = $('#toast'); t.textContent = m; t.classList.add('show'); clearTimeout(t._t); t._t = setTimeout(() => t.classList.remove('show'), 1800); }14 function openSheet(h) { $('#sheet').innerHTML = h; $('#mask').classList.add('show'); }15 function closeSheet() { $('#mask').classList.remove('show'); }16 $('#mask').addEventListener('click', e => { if (e.target.id === 'mask') closeSheet(); });1718 async function adm(action, payload, method) {19 method = method || 'GET';20 try {21 const opt = { method, headers: { 'Content-Type': 'application/json' } };22 let url = 'index.php?c=admin&a=' + action;23 if (method === 'GET' && payload) url += '&' + new URLSearchParams(payload).toString();24 else if (payload) opt.body = JSON.stringify(payload);25 const r = await fetch(url, opt);26 if (!r.ok) throw 0;27 const j = await r.json();28 return j || { ok: 0 };29 } catch (e) { return { ok: 0, msg: '需运行在 PHP 后端环境' }; }30 }31 const esc = s => (s == null ? '' : String(s)).replace(/[&<>"]/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c]));3233 async function login() {34 const r = await adm('login', { user: $('#user').value, pass: $('#pass').value }, 'POST');35 if (r.ok) {36 $('#login').style.display = 'none'; $('#app').style.display = 'block';37 const cfg = await adm('config');38 RO = !!(cfg.read_only);39 $('#robar').style.display = RO ? 'block' : 'none';40 renderNav(); render();41 } else toast(r.msg || '登录失败');42 }43 function logout() { $('#app').style.display = 'none'; $('#login').style.display = 'flex'; }4445 function renderNav() {46 $('#nav').innerHTML = navs.map(n => '<div class="n ' + (n[0] === cur ? 'on' : '') + '" onclick="AD.nav(\'' + n[0] + '\')">' + n[1] + '</div>').join('');47 }48 function render() {49 renderNav();50 if (cur === 'dashboard') return R.dashboard();51 if (cur === 'products') return R.products();52 if (cur === 'orders') return R.orders();53 if (cur === 'members') return R.members();54 if (cur === 'coupons') return R.coupons();55 if (cur === 'reviews') return R.reviews();56 if (cur === 'banners') return R.banners();57 if (cur === 'custom') return R.custom();58 if (cur === 'settings') return R.settings();59 }6061 // 写操作前置检查62 function guard() {63 if (RO) { toast('🔒 后台只读模式已开启,写操作被拦截'); return false; }64 return true;65 }66 function W(r) { if (r.readonly) { RO = true; $('#robar').style.display = 'block'; toast('🔒 ' + r.msg); return false; } if (r.ok) { toast('已保存'); closeSheet(); render(); } else toast(r.msg || '操作失败'); return r.ok; }6768 const STATUS = { pending: ['待支付', 'st-pending'], paid: ['已支付·待制作', 'st-paid'], making: ['制作中', 'st-making'], delivering: ['配送中', 'st-delivering'], done: ['已完成', 'st-done'], canceled: ['已取消', 'st-canceled'], refund: ['退款', 'st-refund'] };6970 const R = {71 async dashboard() {72 const r = await adm('dashboard'); const d = r.ok ? r.data : {};73 const cards = [['今日销售额', '¥' + (d.sales_today || 0)], ['今日订单', d.orders_today || 0], ['订单总数', d.order_total || 0], ['会员总数', d.member_total || 0], ['商品总数', d.product_total || 0], ['待处理', d.pending_orders || 0], ['评价数', d.review_total || 0]];74 const trend = (d.trend || []);75 const max = Math.max(1, ...trend.map(t => +t.s));76 const chart = trend.length ? '<div class="chart">' + trend.map(t => '<div class="c" style="height:' + (Math.max(8, (+t.s / max) * 100)) + '%"><span>' + t.d.slice(5) + '</span></div>').join('') + '</div>' : '<div class="empty">暂无数据</div>';77 const top = (d.top_products || []).map(p => '<div>' + esc(p.name) + ' · 售出 ' + p.qty + '</div>').join('') || '<div class="empty">暂无</div>';78 const lv = (d.level_dist || []).map(l => ({ normal: '普通', silver: '银卡', gold: '金卡', diamond: '钻石' }[l.level] || l.level) + ' ' + l.c).join(' / ');79 $('#content').innerHTML =80 '<div class="cards">' + cards.map(c => '<div class="card"><div class="n">' + c[1] + '</div><div class="l">' + c[0] + '</div></div>').join('') + '</div>' +81 '<div class="panel"><h3>近 7 日销售额趋势</h3>' + chart + '</div>' +82 '<div class="panel mt12"><h3>热销 TOP5</h3>' + top + '</div>' +83 '<div class="panel mt12"><h3>会员等级分布</h3><div class="mini">' + (lv || '—') + '</div></div>';84 },8586 async products() {87 const [list, cats] = await Promise.all([adm('products_list'), adm('categories')]);88 const kinds = (cats.ok ? cats : { kinds: [] }).kinds || [];89 const rows = (list.ok ? list.data : []);90 $('#content').innerHTML = '<div class="panel"><h3>商品管理 <button class="btn pri sm" onclick="AD.addProduct()"' + (RO ? ' disabled' : '') + '>+ 新增</button></h3>' +91 '<table><tr><th>ID</th><th>名称</th><th>品类</th><th>价格</th><th>库存</th><th>状态</th><th>操作</th></tr>' +92 rows.map(p => '<tr><td>' + p.id + '</td><td>' + esc(p.name) + '</td><td>' + esc(p.kind_name || '') + '</td><td>¥' + p.price + '</td><td>' + p.stock + '</td><td><span class="tag ' + (p.status ? 'on' : 'off') + '">' + (p.status ? '在售' : '下架') + '</span></td><td><button class="btn ghost sm" onclick="AD.editProduct(' + p.id + ')">编辑</button> <button class="btn ghost sm" onclick="AD.toggleProduct(' + p.id + ')">上下架</button> <button class="btn danger sm" onclick="AD.delProduct(' + p.id + ')">删</button></td></tr>').join('') + '</table></div>';93 AD._kinds = kinds;94 },95 addProduct() { if (!guard()) return; openSheet('<span class="close" onclick="closeSheet()">×</span><h3>新增商品</h3>' + productForm({}) + '<button class="btn pri block" onclick="AD.saveProduct(0)">保存</button>'); },96 editProduct(id) { if (!guard()) return; adm('products_list').then(r => { const p = r.data.find(x => x.id == id); openSheet('<span class="close" onclick="closeSheet()">×</span><h3>编辑商品 #' + id + '</h3>' + productForm(p) + '<button class="btn pri block" onclick="AD.saveProduct(' + id + ')">保存</button>'); }); },97 saveProduct(id) {98 if (!guard()) return;99 const payload = { id, name: $('#f_name').value, kind_id: $('#f_kind').value, scenes: $('#f_scenes').value, price: $('#f_price').value, original_price: $('#f_oprice').value, stock: $('#f_stock').value, is_new: $('#f_new').checked ? 1 : 0, is_hot: $('#f_hot').checked ? 1 : 0, is_recommend: $('#f_rec').checked ? 1 : 0, description: $('#f_desc').value, ingredients: $('#f_ing').value, allergen: $('#f_all').value, shelf_life: $('#f_life').value, advice: $('#f_advice').value, images: $('#f_images').value, tags: $('#f_tags').value };100 adm('product_save', payload, 'POST').then(W);101 },102 toggleProduct(id) { if (!guard()) return; adm('product_toggle', { id }, 'POST').then(W); },103 delProduct(id) { if (!guard()) return; if (!confirm('确认删除该商品?')) return; adm('product_delete', { id }, 'POST').then(W); },104105 async orders() {106 const r = await adm('orders_list');107 const rows = (r.ok ? r.data : []);108 const opts = Object.keys(STATUS).map(k => '<option value="' + k + '">' + STATUS[k][0] + '</option>').join('');109 $('#content').innerHTML = '<div class="panel"><h3>订单管理 <span class="mini">(只读模式下状态变更被拦截)</span></h3>' +110 '<table><tr><th>单号</th><th>收货人</th><th>金额</th><th>状态</th><th>操作</th></tr>' +111 rows.map(o => '<tr><td>' + o.order_no + '</td><td>' + esc(o.contact_name) + '</td><td>¥' + o.pay_amount + '</td><td><span class="st ' + (STATUS[o.status] || ['', ''])[1] + '">' + (STATUS[o.status] || ['', ''])[0] + '</span></td><td><select id="os_' + o.id + '">' + opts + '</select> <button class="btn ghost sm" onclick="AD.setOrder(' + o.id + ')">更新</button></td></tr>').join('') + '</table></div>';112 rows.forEach(o => { const s = $('#os_' + o.id); if (s) s.value = o.status; });113 },114 setOrder(id) { if (!guard()) return; const st = $('#os_' + id).value; adm('order_update_status', { id, status: st }, 'POST').then(W); },115116 async members() {117 const r = await adm('members_list');118 const rows = (r.ok ? r.data : []);119 const lvName = { normal: '普通', silver: '银卡', gold: '金卡', diamond: '钻石' };120 $('#content').innerHTML = '<div class="panel"><h3>会员管理</h3><table><tr><th>ID</th><th>昵称</th><th>手机</th><th>等级</th><th>积分</th><th>余额</th><th>操作</th></tr>' +121 rows.map(m => '<tr><td>' + m.id + '</td><td>' + esc(m.username) + '</td><td>' + esc(m.phone) + '</td><td>' + (lvName[m.level] || m.level) + '</td><td>' + m.points + '</td><td>¥' + m.balance + '</td><td><button class="btn ghost sm" onclick="AD.editMember(' + m.id + ')">编辑</button> <button class="btn danger sm" onclick="AD.delMember(' + m.id + ')">删</button></td></tr>').join('') + '</table></div>';122 },123 editMember(id) { if (!guard()) return; adm('members_list').then(r => { const m = r.data.find(x => x.id == id); openSheet('<span class="close" onclick="closeSheet()">×</span><h3>编辑会员 #' + id + '</h3>' + memberForm(m) + '<button class="btn pri block" onclick="AD.saveMember(' + id + ')">保存</button>'); }); },124 saveMember(id) { if (!guard()) return; const p = { id, username: $('#m_user').value, phone: $('#m_phone').value, level: $('#m_level').value, points: $('#m_points').value, balance: $('#m_balance').value, growth: $('#m_growth').value, birthday: $('#m_birth').value }; adm('member_save', p, 'POST').then(W); },125 delMember(id) { if (!guard()) return; if (!confirm('确认删除?')) return; adm('member_delete', { id }, 'POST').then(W); },126127 async coupons() {128 const r = await adm('coupons_list');129 const rows = (r.ok ? r.data : []);130 const typeName = { full_reduce: '满减', discount: '折扣', no_threshold: '无门槛', newcomer: '新人', birthday: '生日' };131 $('#content').innerHTML = '<div class="panel"><h3>优惠券 <button class="btn pri sm" onclick="AD.addCoupon()"' + (RO ? ' disabled' : '') + '>+ 新增</button></h3><table><tr><th>ID</th><th>名称</th><th>类型</th><th>规则</th><th>已领/总量</th><th>操作</th></tr>' +132 rows.map(c => '<tr><td>' + c.id + '</td><td>' + esc(c.name) + '</td><td>' + (typeName[c.type] || c.type) + '</td><td>' + esc(c.desc || '') + '</td><td>' + c.received + '/' + c.total + '</td><td><button class="btn ghost sm" onclick="AD.editCoupon(' + c.id + ')">编辑</button> <button class="btn danger sm" onclick="AD.delCoupon(' + c.id + ')">删</button></td></tr>').join('') + '</table></div>';133 },134 addCoupon() { if (!guard()) return; openSheet('<span class="close" onclick="closeSheet()">×</span><h3>新增优惠券</h3>' + couponForm({}) + '<button class="btn pri block" onclick="AD.saveCoupon(0)">保存</button>'); },135 editCoupon(id) { if (!guard()) return; adm('coupons_list').then(r => { const c = r.data.find(x => x.id == id); openSheet('<span class="close" onclick="closeSheet()">×</span><h3>编辑券 #' + id + '</h3>' + couponForm(c) + '<button class="btn pri block" onclick="AD.saveCoupon(' + id + ')">保存</button>'); }); },136 saveCoupon(id) { if (!guard()) return; const p = { id, name: $('#c_name').value, type: $('#c_type').value, threshold: $('#c_th').value, value: $('#c_val').value, discount: $('#c_dis').value, valid_days: $('#c_days').value, total: $('#c_total').value }; adm('coupon_save', p, 'POST').then(W); },137 delCoupon(id) { if (!guard()) return; if (!confirm('确认删除?')) return; adm('coupon_delete', { id }, 'POST').then(W); },138139 async reviews() {140 const r = await adm('reviews_list');141 const rows = (r.ok ? r.data : []);142 $('#content').innerHTML = '<div class="panel"><h3>评价管理</h3><table><tr><th>商品</th><th>用户</th><th>评分</th><th>内容</th><th>操作</th></tr>' +143 rows.map(rv => '<tr><td>' + esc(rv.pname || '') + '</td><td>' + esc(rv.username || '匿名') + '</td><td>' + '★'.repeat(rv.rating) + '</td><td>' + esc(rv.content).slice(0, 20) + (rv.reply ? ' <span class="mini" style="color:#2bb673">已回复</span>' : '') + '</td><td><button class="btn ghost sm" onclick="AD.replyReview(' + rv.id + ')">回复</button> <button class="btn danger sm" onclick="AD.delReview(' + rv.id + ')">删</button></td></tr>').join('') + '</table></div>';144 },145 replyReview(id) { if (!guard()) return; openSheet('<span class="close" onclick="closeSheet()">×</span><h3>回复评价 #' + id + '</h3><textarea id="r_reply" placeholder="商家回复内容"></textarea><button class="btn pri block mt12" onclick="AD.doReply(' + id + ')">提交回复</button>'); },146 doReply(id) { if (!guard()) return; adm('review_reply', { id, reply: $('#r_reply').value }, 'POST').then(W); },147 delReview(id) { if (!guard()) return; if (!confirm('确认删除?')) return; adm('review_delete', { id }, 'POST').then(W); },148149 async banners() {150 const r = await adm('banners_list');151 const rows = (r.ok ? r.data : []);152 $('#content').innerHTML = '<div class="panel"><h3>首页轮播 <button class="btn pri sm" onclick="AD.addBanner()"' + (RO ? ' disabled' : '') + '>+ 新增</button></h3><table><tr><th>ID</th><th>图标</th><th>标题</th><th>状态</th><th>操作</th></tr>' +153 rows.map(b => '<tr><td>' + b.id + '</td><td style="font-size:22px">' + esc(b.image) + '</td><td>' + esc(b.title) + '</td><td><span class="tag ' + (b.status ? 'on' : 'off') + '">' + (b.status ? '显示' : '隐藏') + '</span></td><td><button class="btn ghost sm" onclick="AD.editBanner(' + b.id + ')">编辑</button> <button class="btn danger sm" onclick="AD.delBanner(' + b.id + ')">删</button></td></tr>').join('') + '</table></div>';154 },155 addBanner() { if (!guard()) return; openSheet('<span class="close" onclick="closeSheet()">×</span><h3>新增轮播</h3>' + bannerForm({}) + '<button class="btn pri block" onclick="AD.saveBanner(0)">保存</button>'); },156 editBanner(id) { if (!guard()) return; adm('banners_list').then(r => { const b = r.data.find(x => x.id == id); openSheet('<span class="close" onclick="closeSheet()">×</span><h3>编辑轮播 #' + id + '</h3>' + bannerForm(b) + '<button class="btn pri block" onclick="AD.saveBanner(' + id + ')">保存</button>'); }); },157 saveBanner(id) { if (!guard()) return; const p = { id, title: $('#b_title').value, image: $('#b_image').value, link: $('#b_link').value, sort: $('#b_sort').value, status: $('#b_status').checked ? 1 : 0 }; adm('banner_save', p, 'POST').then(W); },158 delBanner(id) { if (!guard()) return; if (!confirm('确认删除?')) return; adm('banner_delete', { id }, 'POST').then(W); },159160 async custom() {161 const r = await adm('custom_list');162 const rows = (r.ok ? r.data : []);163 $('#content').innerHTML = '<div class="panel"><h3>定制需求 <span class="mini">(只读模式下审核被拦截)</span></h3><table><tr><th>ID</th><th>用户</th><th>文字</th><th>尺寸</th><th>状态</th><th>操作</th></tr>' +164 rows.map(c => '<tr><td>' + c.id + '</td><td>' + esc(c.username || '') + '</td><td>' + esc(c.text).slice(0, 16) + '</td><td>' + esc(c.size) + '</td><td><span class="tag ' + (c.status === 'approved' ? 'on' : c.status === 'rejected' ? 'off' : '') + '">' + ({ pending: '待审核', approved: '已通过', rejected: '已拒绝' }[c.status] || c.status) + '</span></td><td><button class="btn ghost sm" onclick="AD.setCustom(' + c.id + ',\'approved\')">通过</button> <button class="btn ghost sm" onclick="AD.setCustom(' + c.id + ',\'rejected\')">拒绝</button></td></tr>').join('') + '</table></div>';165 },166 setCustom(id, st) { if (!guard()) return; adm('custom_update', { id, status: st }, 'POST').then(W); },167168 async settings() {169 const r = await adm('settings_get');170 const d = (r.ok ? r.data : {});171 $('#content').innerHTML = '<div class="panel"><h3>店铺设置 ' + (RO ? '<span class="tag off">只读</span>' : '') + '</h3>' +172 '<label>店铺名称</label><input id="s_name" value="' + esc(d.shop_name || '') + '">' +173 '<label>客服电话</label><input id="s_phone" value="' + esc(d.phone || '') + '">' +174 '<label>门店地址</label><input id="s_addr" value="' + esc(d.address || '') + '">' +175 '<label>配送费(元)</label><input id="s_fee" value="' + esc(d.delivery_fee || '') + '">' +176 '<label>免配送费门槛(元)</label><input id="s_free" value="' + esc(d.free_delivery_amount || '') + '">' +177 '<label>配送范围(公里)</label><input id="s_range" value="' + esc(d.delivery_range_km || '') + '">' +178 '<label>提前预约(小时)</label><input id="s_adv" value="' + esc(d.delivery_advance_hours || '') + '">' +179 '<label>营业时间</label><input id="s_open" value="' + esc(d.open_time || '') + '">' +180 '<label>公告说明</label><textarea id="s_notice">' + esc(d.notice || '') + '</textarea>' +181 '<button class="btn pri block" onclick="AD.saveSettings()" ' + (RO ? 'disabled' : '') + '>保存设置</button>' +182 (RO ? '<div class="mini" style="color:#b26a00;margin-top:8px">🔒 当前为只读模式,保存按钮已禁用。</div>' : '') + '</div>';183 },184 saveSettings() { if (!guard()) return; const p = { shop_name: $('#s_name').value, phone: $('#s_phone').value, address: $('#s_addr').value, delivery_fee: $('#s_fee').value, free_delivery_amount: $('#s_free').value, delivery_range_km: $('#s_range').value, delivery_advance_hours: $('#s_adv').value, open_time: $('#s_open').value, notice: $('#s_notice').value }; adm('settings_save', p, 'POST').then(W); }185 };186187 function productForm(p) {188 p = p || {};189 const kindOpts = (AD._kinds || []).map(k => '<option value="' + k.id + '" ' + (k.id == p.kind_id ? 'selected' : '') + '>' + esc(k.name) + '</option>').join('');190 return '<label>名称</label><input id="f_name" value="' + esc(p.name || '') + '">' +191 '<label>品类</label><select id="f_kind">' + kindOpts + '</select>' +192 '<label>适用场景(| 分隔,如 生日蛋糕|儿童节)</label><input id="f_scenes" value="' + esc(p.scenes || '') + '">' +193 '<label>售价 / 原价</label><div class="bar"><input id="f_price" placeholder="售价" value="' + (p.price || '') + '"><input id="f_oprice" placeholder="原价" value="' + (p.original_price || '') + '"></div>' +194 '<label>库存</label><input id="f_stock" value="' + (p.stock != null ? p.stock : 99) + '">' +195 '<label><input type="checkbox" id="f_new" ' + (p.is_new ? 'checked' : '') + '> 新品 <input type="checkbox" id="f_hot" ' + (p.is_hot ? 'checked' : '') + '> 热销 <input type="checkbox" id="f_rec" ' + (p.is_recommend ? 'checked' : '') + '> 推荐</label>' +196 '<label>描述</label><textarea id="f_desc">' + esc(p.description || '') + '</textarea>' +197 '<label>配料 / 过敏原</label><div class="bar"><input id="f_ing" value="' + esc(p.ingredients || '') + '"><input id="f_all" value="' + esc(p.allergen || '') + '"></div>' +198 '<label>保质期 / 食用建议</label><div class="bar"><input id="f_life" value="' + esc(p.shelf_life || '') + '"><input id="f_advice" value="' + esc(p.advice || '') + '"></div>' +199 '<label>图片 emoji(| 分隔,如 🍓|🍰)</label><input id="f_images" value="' + esc(p.images || '🎂') + '">' +200 '<label>标签</label><input id="f_tags" value="' + esc(p.tags || '') + '">';201 }202 function memberForm(m) {203 m = m || {};204 return '<label>昵称</label><input id="m_user" value="' + esc(m.username || '') + '">' +205 '<label>手机</label><input id="m_phone" value="' + esc(m.phone || '') + '">' +206 '<label>等级</label><select id="m_level"><option value="normal" ' + (m.level == 'normal' ? 'selected' : '') + '>普通</option><option value="silver" ' + (m.level == 'silver' ? 'selected' : '') + '>银卡</option><option value="gold" ' + (m.level == 'gold' ? 'selected' : '') + '>金卡</option><option value="diamond" ' + (m.level == 'diamond' ? 'selected' : '') + '>钻石</option></select>' +207 '<label>积分 / 成长值</label><div class="bar"><input id="m_points" value="' + (m.points || 0) + '"><input id="m_growth" value="' + (m.growth || 0) + '"></div>' +208 '<label>储值余额</label><input id="m_balance" value="' + (m.balance || 0) + '">' +209 '<label>生日</label><input id="m_birth" value="' + esc(m.birthday || '') + '">';210 }211 function couponForm(c) {212 c = c || {};213 const t = c.type || 'full_reduce';214 return '<label>名称</label><input id="c_name" value="' + esc(c.name || '') + '">' +215 '<label>类型</label><select id="c_type"><option value="full_reduce" ' + (t == 'full_reduce' ? 'selected' : '') + '>满减</option><option value="discount" ' + (t == 'discount' ? 'selected' : '') + '>折扣</option><option value="no_threshold" ' + (t == 'no_threshold' ? 'selected' : '') + '>无门槛</option><option value="newcomer" ' + (t == 'newcomer' ? 'selected' : '') + '>新人</option><option value="birthday" ' + (t == 'birthday' ? 'selected' : '') + '>生日</option></select>' +216 '<label>满减门槛 / 抵扣金额</label><div class="bar"><input id="c_th" placeholder="门槛(满减)" value="' + (c.threshold || 0) + '"><input id="c_val" placeholder="金额/无门槛值" value="' + (c.value || 0) + '"></div>' +217 '<label>折扣(0.8=8折)</label><input id="c_dis" value="' + (c.discount || 1) + '">' +218 '<label>有效期(天) / 总量</label><div class="bar"><input id="c_days" value="' + (c.valid_days || 30) + '"><input id="c_total" value="' + (c.total || 999) + '"></div>';219 }220 function bannerForm(b) {221 b = b || {};222 return '<label>图标 emoji</label><input id="b_image" value="' + esc(b.image || '🎂') + '">' +223 '<label>标题</label><input id="b_title" value="' + esc(b.title || '') + '">' +224 '<label>跳转(#home/#category/#member)</label><input id="b_link" value="' + esc(b.link || '#home') + '">' +225 '<label>排序</label><input id="b_sort" value="' + (b.sort || 0) + '">' +226 '<label><input type="checkbox" id="b_status" ' + (b.status ? 'checked' : '') + '> 显示</label>';227 }228229 return { login, logout, nav: v => { cur = v; render(); }, render,230 addProduct: R.addProduct, editProduct: R.editProduct, saveProduct: R.saveProduct, toggleProduct: R.toggleProduct, delProduct: R.delProduct,231 setOrder: R.setOrder, editMember: R.editMember, saveMember: R.saveMember, delMember: R.delMember,232 addCoupon: R.addCoupon, editCoupon: R.editCoupon, saveCoupon: R.saveCoupon, delCoupon: R.delCoupon,233 replyReview: R.replyReview, doReply: R.doReply, delReview: R.delReview,234 addBanner: R.addBanner, editBanner: R.editBanner, saveBanner: R.saveBanner, delBanner: R.delBanner,235 setCustom: R.setCustom, saveSettings: R.saveSettings };236})();237