卷十息加载中...

页面加载异常

卷十息

身边即世界,咫尺解烦忧

登录
还没有账号?立即注册
我已阅读并同意《用户协议》《隐私政策》
注册
已有账号?去登录
← 返回
会员中心
1豆=1元,豆可兑换会员
当前等级
{{myMembership.level==='premium'?'高级会员':myMembership.level==='normal'?'普通会员':'免费用户'}}
到期:{{fmtTime(myMembership.expires_at)}}
剩余豆
{{myInfo.beans||0}}
配额使用
热点查询:{{myMembership.hotspot_used||0}}/{{myMembership.hotspot_limit||3}}
跑腿发布:{{myMembership.errand_used||0}}/{{myMembership.errand_limit||0}}
权益对比
功能 免费 普通 高级
看帖/发帖
点赞/差评
查周边热点3次/天30次/月♾️
发供给扣豆扣豆扣豆
发跑腿10次/月♾️
接单
守护出行
守护关系1组5组♾️
轨迹回放
走散预警
多人团3人10人♾️
开通会员
普通会员
30豆/月
热点30次+跑腿10次
高级会员
98豆/月
热点+跑腿不限次
豆兑换会员
赚豆方式
📅 每日签到 +1豆
✍️ 发帖 +1豆
👍 被点赞 +1信誉
🤝 完成供给 +2豆
← 返回我的帖子
暂无帖子
{{p.content}}
{{fmtTime(p.created_at)}} 👍 {{p.likes}} 👎 {{p.dislikes}}
🤝 供给 {{p.reward_amount}}豆
← 返回豆明细
当前余额
{{myInfo.beans||0}} 豆
暂无记录
{{l.reason}}
{{fmtTime(l.created_at)}}
{{l.amount>0?'+':''}}{{l.amount}}
← 返回举报管理
暂无举报记录
{{fmtTime(r.created_at)}}
原因:{{r.reason}}
帖子:{{r.post_content||'已删除'}}
举报人:{{r.reporter_nick||'未知'}} | 帖子作者:{{r.post_owner_nick||'未知'}}
← 返回消息中心{{unreadCount}}全部已读
暂无消息
{{n.title||'系统消息'}}
{{n.content}}
{{fmtTime(n.created_at)}}
已处理
← 返回我的举报
暂无举报记录
{{fmtTime(r.created_at)}}
原因:{{r.reason}}
帖子:{{r.post_content||'已删除'}}
隐私政策

更新日期:2026年6月6日

一、我们收集哪些信息

1. 注册信息:手机号(用于实名认证)、昵称、密码。

2. 位置信息:仅在您主动开启定位或使用"出行"功能时获取,且仅在出行期间临时共享,出行结束即清除。

3. 帖子内容:您发布的文字和图片。

二、我们如何使用信息

1. 手机号仅用于账号注册和登录验证,不会对外展示。

2. 位置信息仅用于"出行报备"功能,由出行者主动发起共享,到达目的地或出行结束后自动停止共享并清除轨迹数据。

3. 帖子内容用于社区展示,帖子保留6个月后自动清除。

三、信息共享与披露

1. 位置共享:仅在出行期间,同行团员及已绑定的守护人可查看位置,出行结束即不可见。

2. 我们不会将您的个人信息出售或分享给第三方。

3. 依法配合公安机关调取涉案信息时,我们将锁定并保留相关数据。

四、数据保留期限

1. 位置日志:出行结束即清除。

2. 帖子内容:保留6个月后自动清除,涉案帖子锁定保存。

3. 系统日志:保留6个月。

4. 实名信息:服务终止后至少保留2年。

五、您的权利

1. 您可随时关闭定位、结束出行、解除守护关系。

2. 出行结束后,所有位置数据自动清除。

3. 您可举报违规内容,我们将依法处理。

六、守护模式说明

守护模式遵循"出行报备"原则:由出行者主动发起位置共享,而非被动被追踪。控制权始终在出行者手中。

· 出行者主动创建/加入出行后,位置才对守护人可见

· 到达目的地后,出行自动结束,位置数据清除

· 任何团员均可结束出行

· 出行结束后,守护人无法再获取位置信息

七、联系我们

如有疑问,请通过App内反馈功能联系我们。

用户协议

更新日期:2026年6月6日

一、服务说明

卷十息是一款基于位置的社区服务应用,提供周边动态、出行报备、悬赏供给等功能。使用本应用即表示您同意本协议。

二、用户行为规范

1. 不得发布违法、暴力、色情、虚假、侵权等内容。

2. 不得利用本应用进行骚扰、诈骗等违法行为。

3. 违规内容将被删除,严重者将封禁账号并配合公安机关处理。

三、实名认证

根据《网络安全法》要求,用户需通过手机号完成实名注册。后台实名、前台自愿。

四、位置信息

位置功能为可选增强功能,不强制索取。出行报备功能由用户主动发起,出行结束自动停止共享。

五、免责声明

1. 用户发布的内容由用户自行负责。

2. 悬赏交易由双方自行协商,平台不承担担保责任。

3. 因不可抗力导致服务中断,平台不承担责任。

{{hasLocation?locText:'定位已关闭'}}

500米看世界

🔥热力推荐

暂无帖子
成为第一个发言的人吧!

{{(p.nickname||'?')[0]}}
{{p.nickname}}
{{fmtTime(p.created_at)}}
🤝供给 {{fmtDist(p.distance)}}
{{p.content}}
{{p.bounty_beans}}豆 {{(p.bounty_status==='claimed'?'已接单':p.bounty_status==='done'?'已完成':'供给中')}}
{{c.nickname||'匿名'}} {{c.content}} {{fmtTime(c.created_at)}}
{{posts.length>=20?'下拉加载更多':'没有更多了'}}
发帖 ← 退出
{{pubContent.length}}/500
⚠️ 请勿委托购买处方药,线下交易由双方自行协商,平台不参与资金往来
诚意豆(必填)
{{bountyBeans}} 豆
发布需求需放置诚意豆,完成后自动转给帮忙人,避免虚假需求
服务定价
{{errandReward}} 豆
需求方完成确认后自动转给你,体现你的服务价值
💡 描述你能提供的服务,如:修电器、通水管、开锁、代买等
⚠️ 请勿代购处方药,交易由双方自行协商,平台不参与资金往来
发布
帖子保留6个月后自动清除

🚌 出行管理

主动报备,安全出行
← 退出
{{activeTrip.to_name||'未知目的地'}} {{activeTrip.status==='ongoing'?'进行中':activeTrip.status==='arrived'?'已到达':'已结束'}}
邀请码: {{activeTrip.join_code}} 复制
{{fmtTime(activeTrip.created_at)}} 出发 · 约{{Math.round(activeTrip.duration/60*10)/10}}小时
团队状态: {{groupView.dispersion==='together'?'在一起':groupView.dispersion==='nearby'?'较近':'已走散'}}
{{(m.nickname||'?')[0]}}
{{m.nickname||'团员'}}
{{fmtDist(m.distance)}}

暂无进行中的出行
创建或加入一个出行吧

出行记录
{{t.to_name||'出行'}} {{t.status==='arrived'?'已到达':'已结束'}}
{{fmtTime(t.created_at)}}
{{activeTrip.to_name||'未知目的地'}} 进行中
{{fmtTime(activeTrip.created_at)}} 出发
邀请守护人

请先创建或加入出行,再邀请守护人

收到的邀请
{{(inv.inviter_name||'?')[0]}}
{{inv.inviter_name||'用户'}}
邀请你守护「{{inv.destination||'出行'}}」
我守护的
{{(g.ward_name||'?')[0]}}
{{g.ward_name||'被守护人'}}
绑定于 {{fmtTime(g.created_at)}}
守护我的
{{(g.guardian_name||'?')[0]}}
{{g.guardian_name||'守护人'}}
绑定于 {{fmtTime(g.created_at)}}

暂无守护关系
邀请家人绑定,出行时共享位置

🤝 身边供给

← 退出

暂无供给信息
邻里供给,身边人帮身边人

定价{{b.reward_amount||0}}豆{{b.beans||0}}豆
{{b.status==='open'?'供给中':b.status==='claimed'?'已接单':'已完成'}}
{{b.content}}
{{b.nickname||'匿名'}} · {{fmtTime(b.created_at)}} · {{fmtDist(b.distance)}}
{{b.bounty_type==='errand'?'响应人':'帮忙人'}}: {{b.claim_nickname}}
📞 {{b.other_phone}}
已评价✅
← 退出
{{(myInfo.nickname||'?')[0]}}
{{myInfo.nickname||'未登录'}}
{{myInfo.mood||'正面'}} · 注册{{fmtDays(myInfo.created_at)}}天
{{myInfo.post_count||0}}
发帖
{{myInfo.like_count||0}}
获赞
{{myInfo.reputation||0}}
信誉
{{myInfo.beans||0}}
🔔 消息中心 {{unreadCount}}
每日签到 {{signedToday?'已签到✅':'签到+1豆'}} ›
会员中心
我的帖子
举报管理
豆明细
我的举报
📍 生活半径 🔒会员
身边 发布 出行 供给 我的
💬 {{guardChatOtherName}} 关闭
暂无消息
{{m.content}}
匿名评价
评价完全匿名,对方无法看到是谁评的
评分
取消 提交评价

对话 {{chatOtherNick}} 📋信誉📞 {{bounties.find(function(x){return x.id===chatBountyId}).other_phone}}

关闭
双方都点击后可互看电话
✅ 双方已谈妥,电话已互开
{{m.sender_nickname}}
{{m.content}}
暂无消息,开始对话吧
预览图片
选择你的位置关闭
{{r.name}}
{{r.address}}
{{(repU.nickname||'?')[0]}}
{{repU.nickname||'匿名'}}
{{repU.membership.level==='premium'?'高级会员':'普通会员'}} 免费用户 {{repU.mood||'正面'}}
{{repU.reputation||0}}
信誉值
{{repU.received_likes||0}}
👍 获赞
{{repU.received_dislikes||0}}
👎 获差评
{{repU.hotspot_received||0}}
🔥 推荐上热门
{{repTip}}
📥 我获得的
信誉值{{repU.reputation||0}}
获赞{{repU.received_likes||0}}
获差评{{repU.received_dislikes||0}}
被举报{{repU.reported_count||0}}
被人帮过{{repU.help_received||0}} 次
爽约/取消{{repU.no_shows||0}} 次
获得热力推荐{{repU.hotspot_received||0}} 次
📤 我给出的
给出赞{{repU.given_likes||0}}
给出差评{{repU.given_dislikes||0}}
给出热力推荐{{repU.given_hotspots||0}}
给出举报{{repU.given_reports||0}}
帮助过别人{{repU.help_given||0}} 次
💡 信誉说明
信誉值体现社区成员的人品和可信度。帮人+1,获赞+1;差评-2,被举报-1,爽约扣信誉。信誉越高,越容易获得邻里信任和供给机会。
关闭
举报原因
{{r}}
提交举报
邀请守护人×
输入对方手机号,邀请成为你的守护人
大市场
之前插入 // 需要:店铺详情页、下单页、消费码页、商家中心 // 所有DOM放在#app外面(与marketOverlay同策略) // === 店铺详情覆盖层 === document.addEventListener('DOMContentLoaded', function() { // 店铺详情页DOM(插在merchantApplyPopup之后) var shopHTML = ''; // 下单页 shopHTML += ''; // 消费码页 shopHTML += ''; // 商家中心覆盖层 shopHTML += ''; // 插入DOM var applyPopup = document.getElementById('merchantApplyPopup'); if (applyPopup && applyPopup.nextSibling) { var temp = document.createElement('div'); temp.innerHTML = shopHTML; while (temp.firstChild) { applyPopup.parentNode.insertBefore(temp.firstChild, applyPopup.nextSibling); } } else { document.body.insertAdjacentHTML('beforeend', shopHTML); } }); // === 全局变量 === var shopMerchant = null; var shopItems = []; var orderCart = []; var currentOrder = null; var merchantCenterData = null; // === 店铺详情 === function openShop(merchantId) { var vm = window.__vueApp; if (!vm || !vm.token) { if(typeof vant!=='undefined') vant.showToast('请先登录'); return; } document.getElementById('marketOverlay').style.display = 'none'; document.getElementById('shopOverlay').style.display = 'flex'; document.getElementById('shopContent').innerHTML = '
加载中...
'; document.getElementById('shopBottomBar').style.display = 'none'; fetch('/api/merchants/' + merchantId + '/detail', {headers: {'Authorization': 'Bearer ' + vm.token}}) .then(function(r) { return r.json(); }) .then(function(d) { shopMerchant = d.merchant; shopItems = d.merchant.items || []; document.getElementById('shopTitle').textContent = shopMerchant.name || '店铺'; document.getElementById('shopBottomBar').style.display = 'block'; renderShop(); }) .catch(function() { document.getElementById('shopContent').innerHTML = '
加载失败
'; }); } function renderShop() { var m = shopMerchant; var items = shopItems; var catMap = {eat:'吃🍜',wear:'穿👕',live:'住🏠',use:'用🛒',go:'行🚗'}; var html = ''; // 顶部信息 html += '
'; if (m.cover_image) { html += ''; } html += '
'; html += '' + (m.name||'') + ''; if (m.verified) html += '已认证'; html += '
'; html += '
'; html += '' + (catMap[m.category]||m.category||'') + ''; if (m.rating) html += '⭐' + parseFloat(m.rating).toFixed(1) + ''; if (m.avg_price) html += '人均¥' + parseFloat(m.avg_price).toFixed(0) + ''; html += '
'; if (m.hours) html += '
🕐 ' + m.hours + '
'; if (m.address) html += '
📍 ' + m.address + '
'; if (m.phone) html += '
📞 电话' + (m.lat&&m.lng ? '🗺️ 导航' : '') + '
'; if (m.description) html += '
' + m.description + '
'; if (m.support_invoice) html += '
🧾 支持开具发票
'; html += '
'; // 商品列表 if (items.length > 0) { html += '
'; html += '
🍽️ 商品/服务
'; // 分类Tab var cats = []; var catSet = {}; items.forEach(function(it) { if (it.category && !catSet[it.category]) { catSet[it.category] = true; cats.push(it.category); } }); if (cats.length > 1) { html += '
'; html += '
全部
'; cats.forEach(function(c) { html += '
' + c + '
'; }); html += '
'; } // 商品卡片 html += '
'; items.forEach(function(it) { html += '
'; if (it.image) { html += ''; } else { html += '
🍽
'; } html += '
'; html += '
' + (it.name||'') + '
'; if (it.description) html += '
' + it.description + '
'; var specs = it.specs || {}; var specKeys = Object.keys(specs); if (specKeys.length > 0) { html += '
'; specKeys.forEach(function(k) { html += k + ':' + specs[k] + ' '; }); html += '
'; } html += '
'; html += '¥' + parseFloat(it.price).toFixed(2) + ''; html += ''; html += '
'; html += '
'; }); html += '
'; } else { html += '
📋
商家暂未添加商品
可直接到店消费
'; } document.getElementById('shopContent').innerHTML = html; } function filterShopItems(cat) { document.querySelectorAll('.shop-cat-tab').forEach(function(el) { if (el.getAttribute('data-cat') === cat) { el.style.background = '#ff6034'; el.style.color = '#fff'; el.style.fontWeight = '600'; } else { el.style.background = '#f0f0f0'; el.style.color = '#666'; el.style.fontWeight = 'normal'; } }); document.querySelectorAll('.shop-item-card').forEach(function(el) { if (!cat || el.getAttribute('data-category') === cat) { el.style.display = 'flex'; } else { el.style.display = 'none'; } }); } function closeShop() { document.getElementById('shopOverlay').style.display = 'none'; document.getElementById('shopBottomBar').style.display = 'none'; shopMerchant = null; shopItems = []; orderCart = []; } // === 下单 === function addToCart(itemId) { var item = shopItems.find(function(i) { return i.id === itemId; }); if (!item) return; var existing = orderCart.find(function(c) { return c.item_id === itemId; }); if (existing) { existing.quantity += 1; } else { orderCart.push({ item_id: item.id, name: item.name, price: parseFloat(item.price), quantity: 1, specs: item.specs || {} }); } if(typeof vant!=='undefined') vant.showToast(item.name + ' 已加入'); } function startOrder() { if (!orderCart.length) { // 没有选商品也可以下单(直接到店) } document.getElementById('orderOverlay').style.display = 'flex'; renderOrder(); } function renderOrder() { var html = ''; html += '
'; html += '
' + (shopMerchant.name||'') + '
'; if (orderCart.length > 0) { orderCart.forEach(function(it, idx) { html += '
'; html += '
' + it.name + '
'; html += '
¥' + it.price.toFixed(2) + '
'; html += '
'; html += ''; html += '' + it.quantity + ''; html += ''; html += '
'; }); } else { html += '
未选商品,直接到店消费
'; } html += '
'; // 备注 html += '
'; html += '
备注
'; html += ''; html += '
'; // 提示 html += '
💡 本平台不收款,到店实际价格为准
下单后生成消费码,到店出示即可
'; document.getElementById('orderContent').innerHTML = html; updateOrderTotal(); } function changeQty(idx, delta) { orderCart[idx].quantity += delta; if (orderCart[idx].quantity <= 0) orderCart.splice(idx, 1); renderOrder(); } function updateOrderTotal() { var total = 0; orderCart.forEach(function(it) { total += it.price * it.quantity; }); document.getElementById('orderTotal').textContent = '¥' + total.toFixed(2); } function closeOrderPage() { document.getElementById('orderOverlay').style.display = 'none'; } function submitOrder() { var vm = window.__vueApp; if (!vm || !vm.token) { if(typeof vant!=='undefined') vant.showToast('请先登录'); return; } if (!shopMerchant) return; var items = orderCart.map(function(it) { return { item_id: it.item_id, name: it.name, price: it.price, quantity: it.quantity, specs: it.specs }; }); var remark = ''; var remEl = document.getElementById('orderRemark'); if (remEl) remark = remEl.value.trim(); var btn = document.getElementById('submitOrderBtn'); btn.disabled = true; btn.textContent = '提交中...'; fetch('/api/merchant-orders', { method: 'POST', headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + vm.token}, body: JSON.stringify({ merchant_id: shopMerchant.id, items: items, remark: remark }) }).then(function(r) { return r.json(); }).then(function(d) { btn.disabled = false; btn.textContent = '提交订单'; if (d.error) { if(typeof vant!=='undefined') vant.showToast(d.error); return; } currentOrder = d.order; orderCart = []; closeOrderPage(); closeShop(); showConsumeCode(d.order); }).catch(function() { btn.disabled = false; btn.textContent = '提交订单'; if(typeof vant!=='undefined') vant.showToast('下单失败'); }); } // === 消费码页面 === function showConsumeCode(order) { document.getElementById('consumeCodeOverlay').style.display = 'flex'; currentOrder = order; renderConsumeCode(); } function renderConsumeCode() { var o = currentOrder; if (!o) return; var items = typeof o.items === 'string' ? JSON.parse(o.items) : (o.items || []); var statusMap = {pending:'待到店', confirmed:'已核销', cancelled:'已取消', expired:'已过期'}; var statusColor = {pending:'#ff9800', confirmed:'#07c160', cancelled:'#999', expired:'#999'}; var html = ''; // 消费码大字 html += '
'; html += '
到店出示此消费码
'; html += '
' + o.consume_code + '
'; // 二维码占位(用canvas生成) html += ''; html += '
商家扫码或输码核销
'; html += '
'; // 订单状态 html += '
'; html += '
'; html += '订单状态'; html += '' + (statusMap[o.status]||o.status) + ''; html += '
'; html += '
订单号:' + o.order_no + '
'; html += '
下单时间:' + new Date(o.created_at).toLocaleString() + '
'; if (o.expire_at) html += '
有效期至:' + new Date(o.expire_at).toLocaleString() + '
'; html += '
'; // 商品明细 if (items.length > 0) { html += '
'; html += '
商品明细
'; items.forEach(function(it) { html += '
'; html += '' + it.name + ' ×' + it.quantity + ''; html += '¥' + (it.price * it.quantity).toFixed(2) + ''; html += '
'; }); html += '
'; html += '合计¥' + parseFloat(o.total_price).toFixed(2) + ''; html += '
'; html += '
以到店实际价格为准
'; html += '
'; } // 备注 if (o.remark) { html += '
'; html += '
备注
'; html += '
' + o.remark + '
'; html += '
'; } // 操作按钮 if (o.status === 'pending') { html += ''; } // 发票按钮(已核销后) if (o.status === 'confirmed') { if (shopMerchant && shopMerchant.support_invoice) { html += ''; } // 导出消费清单图片 html += ''; } document.getElementById('consumeCodeContent').innerHTML = html; // 生成二维码 setTimeout(function() { generateQR(o.consume_code); }, 100); } function generateQR(code) { var canvas = document.getElementById('qrCanvas'); if (!canvas) return; // 简易二维码:用方格矩阵模拟(无需外部库) var ctx = canvas.getContext('2d'); var size = 160; var cellSize = 4; var modules = Math.floor(size / cellSize); ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, size, size); ctx.fillStyle = '#333'; // 用消费码生成伪随机矩阵 var seed = 0; for (var i = 0; i < code.length; i++) seed += code.charCodeAt(i) * (i + 1); for (var r = 0; r < modules; r++) { for (var c = 0; c < modules; c++) { seed = (seed * 1103515245 + 12345) & 0x7fffffff; if (seed % 3 !== 0) { ctx.fillRect(c * cellSize, r * cellSize, cellSize, cellSize); } } } // 中心写消费码 ctx.fillStyle = '#fff'; ctx.fillRect(size/2-30, size/2-10, 60, 20); ctx.fillStyle = '#ff6034'; ctx.font = 'bold 14px monospace'; ctx.textAlign = 'center'; ctx.fillText(code, size/2, size/2+5); } function closeConsumeCode() { document.getElementById('consumeCodeOverlay').style.display = 'none'; } function cancelOrder(oid) { var vm = window.__vueApp; if (!confirm('确定取消订单?')) return; fetch('/api/merchant-orders/' + oid + '/cancel', { method: 'POST', headers: {'Authorization': 'Bearer ' + vm.token} }).then(function(r) { return r.json(); }).then(function(d) { if (d.error) { if(typeof vant!=='undefined') vant.showToast(d.error); return; } if(typeof vant!=='undefined') vant.showToast('订单已取消'); if (currentOrder) currentOrder.status = 'cancelled'; renderConsumeCode(); }).catch(function() { if(typeof vant!=='undefined') vant.showToast('操作失败'); }); } function requestInvoice(oid) { var title = prompt('发票抬头:'); if (!title) return; var tax_no = prompt('税号(选填):') || ''; var email = prompt('接收邮箱(选填):') || ''; var vm = window.__vueApp; fetch('/api/merchant-orders/' + oid + '/invoice', { method: 'POST', headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + vm.token}, body: JSON.stringify({title: title, tax_no: tax_no, email: email}) }).then(function(r) { return r.json(); }).then(function(d) { if (d.error) { if(typeof vant!=='undefined') vant.showToast(d.error); return; } if(typeof vant!=='undefined') vant.showToast('发票申请已提交'); }).catch(function() { if(typeof vant!=='undefined') vant.showToast('申请失败'); }); } function exportReceipt() { // 生成消费清单图片(用canvas绘制) var o = currentOrder; if (!o) return; var items = typeof o.items === 'string' ? JSON.parse(o.items) : (o.items || []); var c = document.createElement('canvas'); c.width = 300; c.height = 400 + items.length * 30; var ctx = c.getContext('2d'); ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, c.width, c.height); ctx.fillStyle = '#333'; ctx.font = 'bold 18px sans-serif'; ctx.textAlign = 'center'; ctx.fillText('卷十息 · 消费清单', 150, 30); ctx.font = '14px sans-serif'; ctx.textAlign = 'left'; ctx.fillText('店名:' + (o.merchant_name || ''), 20, 60); ctx.fillText('订单号:' + o.order_no, 20, 82); ctx.fillText('消费码:' + o.consume_code, 20, 104); ctx.fillText('时间:' + new Date(o.confirmed_at || o.created_at).toLocaleString(), 20, 126); ctx.fillText('─────────────────────', 20, 148); var y = 170; items.forEach(function(it) { ctx.fillText(it.name + ' ×' + it.quantity, 20, y); ctx.textAlign = 'right'; ctx.fillText('¥' + (it.price * it.quantity).toFixed(2), 280, y); ctx.textAlign = 'left'; y += 28; }); ctx.fillText('─────────────────────', 20, y); y += 22; ctx.font = 'bold 16px sans-serif'; ctx.fillText('合计', 20, y); ctx.textAlign = 'right'; ctx.fillText('¥' + parseFloat(o.total_price).toFixed(2), 280, y); ctx.textAlign = 'center'; ctx.font = '12px sans-serif'; ctx.fillStyle = '#999'; y += 24; ctx.fillText('以到店实际价格为准 | 卷十息 · 身边即世界', 150, y); // 下载图片 var link = document.createElement('a'); link.download = '消费清单_' + o.consume_code + '.png'; link.href = c.toDataURL('image/png'); link.click(); } // === 商家中心 === function openMerchantCenter() { var vm = window.__vueApp; if (!vm || !vm.token) { if(typeof vant!=='undefined') vant.showToast('请先登录'); return; } document.getElementById('merchantCenterOverlay').style.display = 'flex'; document.getElementById('merchantCenterContent').innerHTML = '
加载中...
'; fetch('/api/merchant-orders/shop', {headers: {'Authorization': 'Bearer ' + vm.token}}) .then(function(r) { return r.json(); }) .then(function(d) { merchantCenterData = d; renderMerchantCenter(); }) .catch(function(e) { // 不是商家 document.getElementById('merchantCenterContent').innerHTML = '
您还不是商家
请先在大市场申请入驻
'; }); } function renderMerchantCenter() { var d = merchantCenterData; if (!d || !d.merchant) return; var m = d.merchant; var orders = d.orders || []; var pending = orders.filter(function(o) { return o.status === 'pending'; }); var confirmed = orders.filter(function(o) { return o.status === 'confirmed'; }); var catMap = {eat:'吃🍜',wear:'穿👕',live:'住🏠',use:'用🛒',go:'行🚗'}; var html = ''; // 店铺信息卡片 html += '
'; html += '
'; html += '' + (m.name||'') + ''; html += '' + (catMap[m.category]||m.category||'') + ''; if (m.verified) html += '已认证'; html += '
'; html += '
'; html += '今日待核销:' + pending.length + ''; html += '累计完成:' + confirmed.length + ''; html += '
'; html += '
'; // 核销入口 html += '
'; html += '
✅ 核销订单
'; html += '
'; html += ''; html += ''; html += '
'; html += '
'; html += '
'; // 待核销订单列表 html += '
'; html += '
📋 待核销订单 (' + pending.length + ')
'; if (pending.length === 0) { html += '
暂无待核销订单
'; } else { pending.forEach(function(o) { var oItems = typeof o.items === 'string' ? JSON.parse(o.items) : (o.items || []); html += '
'; html += '
'; html += '' + (o.user_name||'用户') + ''; html += '' + o.consume_code + ''; html += '
'; html += '
' + new Date(o.created_at).toLocaleString() + '
'; oItems.forEach(function(it) { html += '
' + it.name + ' ×' + it.quantity + ' ¥' + (it.price*it.quantity).toFixed(2) + '
'; }); if (o.remark) html += '
备注:' + o.remark + '
'; html += '
'; html += ''; html += ''; html += '
'; html += '
'; }); } html += '
'; // 已完成订单 html += '
'; html += '
✅ 已完成 (' + confirmed.length + ')
'; confirmed.slice(0, 10).forEach(function(o) { html += '
'; html += '' + (o.user_name||'') + ' ¥' + parseFloat(o.total_price).toFixed(2) + ' ' + new Date(o.confirmed_at).toLocaleDateString() + ''; if (o.invoice_requested) html += ' 需开票'; html += '
'; }); html += '
'; // 商品管理入口 html += '
'; html += '
🏪 商品管理
'; html += ''; html += '
'; // 电脑端入口 html += '
'; html += '
💻 电脑端管理
'; html += '
在电脑浏览器打开以下地址,可管理店铺和打印清单
'; html += '
https://www.juanshixi.com/merchant.html
'; html += ''; html += '
'; document.getElementById('merchantCenterContent').innerHTML = html; } function closeMerchantCenter() { document.getElementById('merchantCenterOverlay').style.display = 'none'; } function copyText(text) { if (navigator.clipboard) { navigator.clipboard.writeText(text).then(function() { if(typeof vant!=='undefined') vant.showToast('已复制'); }); } else { var inp = document.createElement('input'); inp.value = text; document.body.appendChild(inp); inp.select(); document.execCommand('copy'); document.body.removeChild(inp); if(typeof vant!=='undefined') vant.showToast('已复制'); } } function verifyOrder() { var code = document.getElementById('verifyCodeInput').value.trim(); if (!code || code.length !== 6) { if(typeof vant!=='undefined') vant.showToast('请输入6位消费码'); return; } var vm = window.__vueApp; document.getElementById('verifyResult').innerHTML = '
查询中...
'; fetch('/api/merchant-orders/verify', { method: 'POST', headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + vm.token}, body: JSON.stringify({consume_code: code}) }).then(function(r) { return r.json(); }) .then(function(d) { if (d.error) { document.getElementById('verifyResult').innerHTML = '
' + d.error + '
'; return; } var o = d.order; var oItems = typeof o.items === 'string' ? JSON.parse(o.items) : (o.items || []); var html = '
'; html += '
'; html += '✅ 消费码有效'; html += '' + o.consume_code + ''; html += '
'; html += '
用户:' + (o.user_name||'') + '
'; html += '
下单时间:' + new Date(o.created_at).toLocaleString() + '
'; html += '
'; oItems.forEach(function(it) { html += '
'; html += '' + it.name + ' ×' + it.quantity + ''; html += '¥' + (it.price*it.quantity).toFixed(2) + ''; html += '
'; }); html += '
'; html += '合计¥' + parseFloat(o.total_price).toFixed(2) + ''; html += '
'; html += '
'; if (o.remark) html += '
备注:' + o.remark + '
'; html += ''; html += '
'; document.getElementById('verifyResult').innerHTML = html; }) .catch(function() { document.getElementById('verifyResult').innerHTML = '
查询失败
'; }); } function confirmOrderById(oid) { var vm = window.__vueApp; if (!confirm('确认核销此订单?')) return; fetch('/api/merchant-orders/confirm', { method: 'POST', headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + vm.token}, body: JSON.stringify({order_id: oid}) }).then(function(r) { return r.json(); }) .then(function(d) { if (d.error) { if(typeof vant!=='undefined') vant.showToast(d.error); return; } if(typeof vant!=='undefined') vant.showToast('核销成功'); // 刷新商家中心 openMerchantCenter(); }) .catch(function() { if(typeof vant!=='undefined') vant.showToast('核销失败'); }); } function printReceipt(oid) { // 生成消费清单图片供打印 var d = merchantCenterData; if (!d || !d.orders) return; var o = d.orders.find(function(x) { return x.id === oid; }); if (!o) return; var items = typeof o.items === 'string' ? JSON.parse(o.items) : (o.items || []); var c = document.createElement('canvas'); c.width = 300; c.height = 350 + items.length * 30; var ctx = c.getContext('2d'); ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, c.width, c.height); ctx.fillStyle = '#333'; ctx.font = 'bold 18px sans-serif'; ctx.textAlign = 'center'; ctx.fillText('卷十息 · 消费清单', 150, 30); ctx.font = '14px sans-serif'; ctx.textAlign = 'left'; ctx.fillText('店名:' + (d.merchant.name||''), 20, 60); ctx.fillText('消费码:' + o.consume_code, 20, 82); ctx.fillText('用户:' + (o.user_name||''), 20, 104); ctx.fillText('下单时间:' + new Date(o.created_at).toLocaleString(), 20, 126); ctx.fillText('─────────────────────', 20, 148); var y = 170; items.forEach(function(it) { ctx.fillText(it.name + ' ×' + it.quantity, 20, y); ctx.textAlign = 'right'; ctx.fillText('¥' + (it.price*it.quantity).toFixed(2), 280, y); ctx.textAlign = 'left'; y += 28; }); ctx.fillText('─────────────────────', 20, y); y += 22; ctx.font = 'bold 16px sans-serif'; ctx.fillText('合计', 20, y); ctx.textAlign = 'right'; ctx.fillText('¥' + parseFloat(o.total_price).toFixed(2), 280, y); ctx.textAlign = 'center'; ctx.font = '12px sans-serif'; ctx.fillStyle = '#999'; y += 24; ctx.fillText('以到店实际价格为准 | 卷十息', 150, y); var link = document.createElement('a'); link.download = '消费清单_' + o.consume_code + '.png'; link.href = c.toDataURL('image/png'); link.click(); } // 商品管理(简易版) function openItemManager() { var items = shopItems.length ? shopItems : []; var html = '
'; html += '
'; html += '商品/服务列表'; html += ''; html += '
'; html += '
'; if (items.length === 0) { html += '
暂无商品,点击添加
'; } items.forEach(function(it) { html += '
'; html += '
' + it.name + ' ¥' + parseFloat(it.price).toFixed(2) + '
'; html += '
'; html += ''; html += '
'; }); html += '
'; html += '
'; html += ''; document.getElementById('merchantCenterContent').innerHTML = html; // 加载最新商品列表 var vm = window.__vueApp; var mid = merchantCenterData.merchant.id; fetch('/api/merchants/' + mid + '/items', {headers: {'Authorization': 'Bearer ' + vm.token}}) .then(function(r) { return r.json(); }) .then(function(d) { shopItems = d.items || []; // 重新渲染 var listHtml = ''; if (shopItems.length === 0) { listHtml = '
暂无商品,点击添加
'; } shopItems.forEach(function(it) { listHtml += '
'; listHtml += '
' + it.name + ' ¥' + parseFloat(it.price).toFixed(2) + ''; if (it.category) listHtml += ' ' + it.category + ''; listHtml += '
'; listHtml += ''; listHtml += '
'; }); var listEl = document.getElementById('itemList'); if (listEl) listEl.innerHTML = listHtml; }); } function addItemForm() { var html = '
'; html += '
添加商品/服务
'; html += '
'; html += '
'; html += '
'; html += '
'; html += ''; html += '
'; document.getElementById('addItemArea').innerHTML = html; } function submitNewItem() { var vm = window.__vueApp; var mid = merchantCenterData.merchant.id; var name = document.getElementById('newItemName').value.trim(); var price = document.getElementById('newItemPrice').value; var cat = document.getElementById('newItemCat').value.trim(); var desc = document.getElementById('newItemDesc').value.trim(); if (!name) { if(typeof vant!=='undefined') vant.showToast('请输入名称'); return; } if (!price) { if(typeof vant!=='undefined') vant.showToast('请输入价格'); return; } fetch('/api/merchants/' + mid + '/items', { method: 'POST', headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + vm.token}, body: JSON.stringify({name: name, price: price, category: cat, description: desc}) }).then(function(r) { return r.json(); }) .then(function(d) { if (d.error) { if(typeof vant!=='undefined') vant.showToast(d.error); return; } if(typeof vant!=='undefined') vant.showToast('添加成功'); openItemManager(); // 刷新 }) .catch(function() { if(typeof vant!=='undefined') vant.showToast('添加失败'); }); } function deleteItem(iid) { if (!confirm('确定删除?')) return; var vm = window.__vueApp; var mid = merchantCenterData.merchant.id; fetch('/api/merchants/' + mid + '/items/' + iid, { method: 'DELETE', headers: {'Authorization': 'Bearer ' + vm.token} }).then(function(r) { return r.json(); }) .then(function(d) { if(typeof vant!=='undefined') vant.showToast('已删除'); openItemManager(); }) .catch(function() { if(typeof vant!=='undefined') vant.showToast('删除失败'); }); } // === 修改大市场商家卡片:点击进入店铺 === var _origRenderMerchants = renderMerchants; renderMerchants = function() { if (!marketMerchants.length) { document.getElementById('marketList').innerHTML = '
🏪
附近暂无商家入驻
邻里供给,身边人帮身边人
'; return; } var catMap = {eat:'吃🍜',wear:'穿👕',live:'住🏠',use:'用🛒',go:'行🚗'}; var html = ''; marketMerchants.forEach(function(m) { var dist = m.distance ? (m.distance < 1000 ? Math.round(m.distance) + 'm' : (m.distance/1000).toFixed(1) + 'km') : ''; html += '
'; html += '
'; html += '
' + (m.name||'') + '
'; if (m.verified) html += '已认证'; html += '
'; html += '
'; html += '' + (catMap[m.category]||m.category||'') + ''; if (dist) html += '📍' + dist + ''; if (m.avg_price) html += '人均¥' + parseFloat(m.avg_price).toFixed(0) + ''; if (m.rating) html += '⭐' + parseFloat(m.rating).toFixed(1) + ''; html += '
'; if (m.address) html += '
📍 ' + m.address + '
'; if (m.description) html += '
' + m.description + '
'; html += '
查看店铺 ›
'; html += '
'; }); document.getElementById('marketList').innerHTML = html; }; // === 查看我的订单 === function openMyOrders() { var vm = window.__vueApp; if (!vm || !vm.token) { if(typeof vant!=='undefined') vant.showToast('请先登录'); return; } document.getElementById('consumeCodeOverlay').style.display = 'flex'; document.getElementById('consumeCodeContent').innerHTML = '
加载中...
'; fetch('/api/merchant-orders/my', {headers: {'Authorization': 'Bearer ' + vm.token}}) .then(function(r) { return r.json(); }) .then(function(d) { var orders = d.orders || []; var statusMap = {pending:'待到店', confirmed:'已核销', cancelled:'已取消', expired:'已过期'}; var statusColor = {pending:'#ff9800', confirmed:'#07c160', cancelled:'#999', expired:'#999'}; var html = '
我的订单
'; if (orders.length === 0) { html += '
暂无订单
'; } orders.forEach(function(o) { var items = typeof o.items === 'string' ? JSON.parse(o.items) : (o.items || []); html += '
'; html += '
'; html += '' + (o.merchant_name||'') + ''; html += '' + (statusMap[o.status]||o.status) + ''; html += '
'; items.forEach(function(it) { html += '
' + it.name + ' ×' + it.quantity + '
'; }); html += '
'; html += '¥' + parseFloat(o.total_price).toFixed(2) + ''; html += '' + new Date(o.created_at).toLocaleDateString() + ''; html += '
'; if (o.status === 'pending') { html += '
消费码:' + o.consume_code + '
'; } html += '
'; }); document.getElementById('consumeCodeContent').innerHTML = html; }) .catch(function() { document.getElementById('consumeCodeContent').innerHTML = '
加载失败
'; }); }