微信小程序“找厕所”(小明带你找厕所)从0到1全栈开发实战详解

📅 发布时间:2026/7/8 12:58:33 👁️ 浏览次数:
微信小程序“找厕所”(小明带你找厕所)从0到1全栈开发实战详解
第一章 项目启航背景与需求分析1.1 项目背景解决“急”时之需在城市综合体、老街巷或陌生商圈 “内急”时找不到厕所是常有的事。传统找厕方式依赖路牌局限性大。随着微信小程序“用完即走”的特性普及以及政府对“厕所革命”的数字化推进“找厕所”小程序成为刚需。社会价值福州“福码找厕”、吉林“江城找厕所”等政府主导项目证明这是城市精细化管理的体现。技术演进从早期的React Native APP如小明找厕所V1.0到如今基于LBS的小程序V2.0技术门槛降低用户体验提升。1.2 需求梳理小明带你找厕所V2.0标准参考早期“小明带你找厕所”的开源需求及2025年最新智慧公厕标准我们将功能分为基础版和进阶版。1.2.1 V1.0 核心功能MVP自动定位打开小程序直接定位当前位置。列表展示按距离排序展示周边1公里内的公厕。基础信息显示厕所名称、详细地址、步行距离。跳转导航点击列表项调起微信内置地图或第三方地图APP进行路线规划。1.2.2 V2.0 增强功能当前主流地图撒点在地图上直观展示所有厕所标记Marker支持点击弹窗。路径规划直接在小程序内使用WebSocket或地图SDK进行步行路径规划并显示文字描述如“直行200米后左转”。丰富筛选按24小时开放、有无无障碍设施残疾人厕所、有无厕纸、是否坑位繁忙智能传感器对接进行筛选。用户共建用户上报新厕所以及评价卫生评分、排队时长。1.2.3 非功能性需求数据准确性POI兴趣点数据必须实地采集或对接权威部门数据避免导航到错误地点如福州项目对五城区公厕全覆盖实地采集。合规性严格遵守《个人信息保护法》用户地理位置数据仅用于本次定位不非法倒卖。第二章 系统设计与技术选型2.1 系统架构图采用经典的前后端分离架构前端微信小程序或Taro/Uniapp跨端。后端Node.js/Java/Python 提供API。数据库关系型数据库存用户、评论 地理空间数据库存厕所坐标。地图服务腾讯地图/高德地图SDK。2.2 技术选型详解基于GitHub上的开源项目Free-Public-Toilet-Map和技术社区实践推荐如下组合层次技术栈选型理由小程序前端原生框架 / Taro (React)原生API最全Taro可实现一套代码多端发行Web/App。前端地图腾讯地图小程序SDK微信生态兼容性最好支持路线规划、逆地址解析无需反复调试Key配置。后端服务Node.js Express对于I/O密集型的地理查询请求处理高效开发速度快适合初创项目。数据库MongoDB Mongoose原生支持地理空间索引2dsphere可高效执行$near地理查询查找附近的点。数据缓存Redis缓存热门商圈的厕所列表减轻数据库压力。部署运维Docker / 微信云开发微信云开发自带数据库和云函数免除运维烦恼适合小团队。2.3 数据库设计核心表结构1. 厕所表 (toilets)json{ _id: ObjectId, name: 三坊七巷南侧公厕, // 名称 address: 福州市鼓楼区营房里10号, // 地址 location: { type: Point, coordinates: [119.295, 26.077] // 经度纬度 (GeoJSON格式) }, images: [url1, url2], // 实景图 attributes: { isFree: true, // 是否免费 is24h: true, // 24小时开放 hasPaper: false, // 是否有纸 hasDisabled: true, // 有无障碍设施 hasBabyCare: true, // 有无母婴室 gender: 男女 // 性别 }, openTime: 06:00-22:00, // 开放时间 source: government, // 数据来源: government, user_submit status: active, // 状态: 审核中/已上线/已关闭 createdAt: 2025-01-01 }地理索引创建db.toilets.createIndex( { location : 2dsphere } )2. 用户反馈表 (reviews)json{ _id: ObjectId, toiletId: ObjectId, openId: 用户加密ID, // 注意匿名化 cleanliness: 4, // 卫生评分 1-5 crowdedness: 3, // 拥挤程度 1-5 comment: 很干净有纸巾, photos: [], reportIssue: false // 是否上报故障如门锁坏 }3. 共享卫生间表 (若对接商家)参考吉林市“共享卫生间”模式需包含商家名称、承诺开放时间等。第三章 开发环境搭建与项目初始化3.1 注册与配置注册小程序前往微信公众平台注册小程序获取AppID。下载开发者工具下载最新版IDE。申请地图Key登录腾讯位置服务创建应用勾选“微信小程序”绑定小程序的AppID生成Key用于路线规划、关键词搜索等高阶功能。3.2 项目结构组织小明带你找厕所标准结构texttoilet-weapp/ ├── miniprogram/ │ ├── images/ # 图标资源 │ ├── pages/ │ │ ├── index/ # 首页列表模式 │ │ ├── map/ # 地图模式V2.0核心 │ │ ├── detail/ # 厕所详情含评论、图片 │ │ ├── report/ # 用户上报 │ │ └── about/ # 关于页面 │ ├── utils/ │ │ ├── util.js │ │ ├── ttmap.js # 腾讯地图SDK封装 │ │ └── wxapi.js # 微信API Promise封装 │ ├── app.js │ ├── app.json │ └── app.wxss ├── cloudfunctions/ # 微信云开发函数可选 ├── project.config.json └── README.md此结构参考了早期“小明找厕所”项目的组织方式将地图与列表逻辑分离。第四章 前端核心功能开发4.1 获取用户授权与定位这是所有功能的前提。需处理用户拒绝授权的情况。javascript// utils/location.js function getUserLocation() { return new Promise((resolve, reject) { wx.getSetting({ success: (res) { if (res.authSetting[scope.userLocation]) { // 已授权直接获取位置 wx.getLocation({ type: gcj02, // 返回国测局坐标腾讯/高德使用 success: resolve, fail: reject }); } else { // 未授权引导授权 wx.authorize({ scope: scope.userLocation, success: () { wx.getLocation({ type: gcj02, success: resolve }); }, fail: () { // 引导用户去设置页开启 wx.showModal({ title: 需要位置权限, content: 是否前往设置页面开启位置权限, success: (modalRes) { if (modalRes.confirm) { wx.openSetting(); } } }); reject(new Error(授权失败)); } }); } } }); }); }4.2 列表模式开发 (index页面)数据获取定位成功后调用后端API/api/toilets/nearby?lngxxxlatxxxradius1000。计算距离后端返回距离米前端格式化显示为“距离xxx米”或“xx公里”。UI渲染使用wx:for循环渲染列表。每个Item显示名称、地址、距离、关键图标如24h、厕纸。添加“刷新”按钮或下拉刷新重新获取定位并拉取数据。跳转导航点击Item调用wx.openLocation打开腾讯地图。javascriptwx.openLocation({ latitude: toilet.lat, longitude: toilet.lng, name: toilet.name, address: toilet.address, scale: 18 });4.3 地图模式开发 (map页面)这是“小明带你找厕所V2.0”的标志性功能。地图初始化html!-- map.wxml -- map idmap longitude{{longitude}} latitude{{latitude}} scale{{16}} markers{{markers}} show-location bindmarkertaponMarkerTap bindcontroltaponControlTap stylewidth: 100%; height: 100vh; /map添加标记Markers从API获取附近厕所列表转换为map组件所需的markers数组。javascript// 转换函数 formatMarkers(toilets) { return toilets.map((item, index) ({ id: item._id, latitude: item.location.coordinates[1], longitude: item.location.coordinates[0], iconPath: item.attributes.is24h ? /images/marker_24h.png : /images/marker_normal.png, width: 30, height: 30, callout: { // 气泡弹窗 content: item.name, color: #000, fontSize: 14, borderRadius: 10, bgColor: #fff, padding: 8, display: ALWAYS // 常显或BYCLICK } })); }点击Marker显示详情onMarkerTap事件中获取markerId然后调起底部的半屏详情页或显示路径规划按钮。4.4 路径规划小程序内嵌如果不想跳转到外部地图可以使用腾讯地图小程序JavaScript SDK进行路线规划。引入SDK下载qqmap-wx-jssdk.min.js放入utils。实例化const qqmapsdk new QQMapWX({ key: 你的Key });规划路线javascriptqqmapsdk.direction({ mode: walking, // 步行 from: ${userLat},${userLng}, to: ${toiletLat},${toiletLng}, success: (res) { // res.routes 包含路线步骤可渲染到页面 console.log(res.routes[0].steps); } });第五章 后端API开发Node.js Express MongoDB5.1 项目初始化bashnpm init -y npm install express mongoose cors dotenv创建server.js和.env文件。5.2 连接MongoDBjavascript// config/db.js const mongoose require(mongoose); const connectDB async () { await mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true, }); console.log(MongoDB 连接成功); };5.3 定义数据模型 (Model)javascript// models/Toilet.js const mongoose require(mongoose); const toiletSchema new mongoose.Schema({ name: String, address: String, location: { type: { type: String, enum: [Point], default: Point }, coordinates: { type: [Number], index: 2dsphere } // 关键2dsphere索引 }, attributes: { is24h: Boolean, hasPaper: Boolean, hasDisabled: Boolean }, // ... 其他字段 }); module.exports mongoose.model(Toilet, toiletSchema);5.4 核心接口查找附近的厕所javascript// routes/toilets.js router.get(/nearby, async (req, res) { const { longitude, latitude, radius 2000 } req.query; // radius单位米 if (!longitude || !latitude) { return res.status(400).json({ error: 缺少经纬度参数 }); } try { const toilets await Toilet.find({ location: { $near: { $geometry: { type: Point, coordinates: [parseFloat(longitude), parseFloat(latitude)] }, $maxDistance: parseInt(radius) // 半径内 } }, status: active }).limit(50); // 限制最多50条 // 可以在此处使用mongoose虚拟字段计算距离或者直接返回让前端用 haversine 公式再算一遍 res.json({ success: true, data: toilets, count: toilets.length }); } catch (error) { res.status(500).json({ error: error.message }); } });5.5 数据导入脚本从高德地图POI或者政府公开数据导入。参考开源项目中的import-data.js脚本读取JSON文件批量插入数据库。第六章 数据来源与“共享厕所”模式6.1 数据采集三大途径政府合作最权威如福州“福码找厕”由城管委主导网格员实地采集五城区公厕记录厕位数量、无障碍设施、开放时间并拍摄标准化照片。对接政府现有公厕档案数据库。第三方POI抓取需合规从高德地图/腾讯地图的开放API搜索“公厕”获取基础数据。注意遵守Robots协议和版权。优势覆盖广劣势信息可能滞后如临时关闭不知情。“共享卫生间”模式创新参考吉林市做法动员临街商户麦当劳、肯德基、加油站、机关单位开放内部卫生间。开发重点需要审核机制确保商家按时开放需要标注是“公共厕所”还是“共享厕所”。UGC用户上报用户拍照上传新厕所后台审核后录入。需防恶意刷单。6.2 数据更新与维护动态监测上海徐汇“汇寻厕”通过红外传感监测坑位拥挤度。虽成本较高但可作为未来发展方向。定期复核每季度对POI数据进行电话回访或实地抽样标记已关闭的公厕。第七章 增强功能与用户体验优化7.1 高级筛选与排序在筛选面板中用户可以选择仅看24h营业仅看有厕纸仅看有母婴室按“距离最近”或“评分最高”排序后端需支持动态查询条件javascriptif (filters.is24h) query[attributes.is24h] true;7.2 实时拥挤度需硬件如果有对接IoT设备数据库需新增字段crowdness0: 空闲无人1: 正常少量人2: 拥挤排队前端地图Marker可改变颜色表示拥挤度绿色、橙色、红色。7.3 无障碍模式针对老年人和残障人士提供大字体模式并优先推荐有无障碍设施的厕所。支持语音搜索。第八章 测试、审核与发布8.1 真机调试与兼容性测试iOS与Android两个平台上地图组件的表现略有差异需分别测试。授权测试测试首次拒绝授权、二次授权、关闭授权后重新开启的整个流程。网络切换在弱网环境下如地下室页面加载状态和超时处理是否友好。8.2 域名配置与安全合法域名在微信公众平台配置request合法域名包括你的后端API域名和腾讯地图的域名https://apis.map.qq.com。HTTPS后端API必须强制使用HTTPSWSS协议。数据加密用户openId等敏感信息传输时需加密或使用微信云开发天然防护。8.3 提交审核注意事项类目选择选择“工具-生活服务”。功能完整性审核员会测试核心流程。如果地图是一片空白或点击厕所无反应会被驳回。ICP证纯信息平台一般无需但如果涉及广告或电商需注意。单纯工具类无需额外资质。8.4 灰度发布与正式上线先发布为“体验版”给内部10个成员测试观察日志和报错。无问题后提交审核审核通过后手动点击“发布”。第九章 运营与后期迭代9.1 用户反馈系统内置“反馈”入口收集厕所信息错误关门、搬迁。卫生状况投诉。新点位建议。9.2 数据统计与分析热门搜索哪个商圈搜索量最大考虑增加该区域公厕密度。使用时段发现晚上10点后搜索量大应确保该区域24h厕所足够。跳出率用户是否在看了列表后未导航可能列表信息不够吸引人或位置不准。9.3 商业化探索非盈利组织可忽略公益广告接入政府文明宣传广告。厕所纸巾机扫码广告虽然不直接获利但可以做为服务的一部分。商家导流对“共享厕所”的商家给予一定的曝光度如显示“xx商家欢迎您”实现双赢。第十章 完整代码示例与关键点解析10.1 计算两点距离的工具函数javascript// utils/distance.js function getDistance(lat1, lng1, lat2, lng2) { const radLat1 lat1 * Math.PI / 180.0; const radLat2 lat2 * Math.PI / 180.0; const a radLat1 - radLat2; const b lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0; let s 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b/2),2))); s s * 6378.137; // 地球半径 s Math.round(s * 1000); // 单位米 return s; }10.2 列表页下拉刷新逻辑javascriptPage({ onLoad: function() { this.getLocationAndFetchData(); }, onPullDownRefresh: function() { this.getLocationAndFetchData(() { wx.stopPullDownRefresh(); // 停止刷新动画 }); }, getLocationAndFetchData(callback) { wx.getLocation({ success: (res) { // 调用后端API wx.request({ url: https://你的域名/api/toilets/nearby, data: { longitude: res.longitude, latitude: res.latitude }, success: (res) { this.setData({ toilets: res.data.data }); }, complete: () { callback callback(); } }); } }); } });10.3 使用云开发快速实现后端免运维如果不想自己搭建服务器可使用微信云开发。新建云函数getNearbyToilets。云函数代码Node.js环境javascriptconst cloud require(wx-server-sdk); cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }); const db cloud.database(); const _ db.command; exports.main async (event, context) { const { longitude, latitude, radius 2000 } event; try { return await db.collection(toilets).where({ location: _.geoNear({ geometry: db.Geo.Point(longitude, latitude), maxDistance: radius, minDistance: 0 }) }).get(); } catch (e) { return e; } };小程序端调用wx.cloud.callFunction({ name: getNearbyToilets, data: {...} })。第十一章 总结与展望11.1 项目回顾我们从0到1搭建了一个完整的“找厕所”微信小程序。涵盖了业务从解决民生痛点出发。技术前后端分离、LBS地理查询、地图可视化。数据政府合作与UGC结合。11.2 未来展望AI智慧公厕AI预测基于历史数据预测景区公厕在节假日的人流高峰时段提前预警。室内导航对于大型交通枢纽机场、高铁站引入室内蓝牙定位导航到具体隔间。多模态交互接入微信“听一听”支持语音唤醒“小明带我去厕所”。