☰
基于微信小程序与Flask的公共厕所管理系统设计与实现
2026/10/2 3:50:30 网站建设 项目流程

1. 这个系统到底在解决什么问题:从"找厕所难"到"管厕所烦"

先说一个我自己的亲身经历。去年夏天在某个老城区办事,手机快没电,肚子又不舒服,前后跑了三条街才找到一个挂"正常开放"牌子的公厕,推门进去——地面泡着水,洗手液是空的,卷纸只有半截。我当时第一反应不是抱怨,而是想到了一个问题:城市里的公共厕所数量并不少,为什么使用体验却这么不稳定?后来和一个在街道办做后勤的朋友聊起来,他倒了一肚子苦水:保洁阿姨有没有按时去打扫、设施坏了有没有人报修、耗材用完了有没有人管,全靠纸质记录和电话通知,上级检查时翻台账翻得头大。那一刻我意识到,"找厕所难"和"管厕所烦"其实是同一个系统问题的两面——用户不知道哪座厕所干净可用,管理者不知道每座厕所的真实状态。

这就是"厕所厕ce"公共厕所管理系统最初的动机。项目背景就是这样一个典型的民生服务场景:城市公厕属于典型的低频刚需设施,覆盖范围广、分布零散,但又与每个人的生活息息相关。作为一个基于微信小程序 + Python Flask 框架开发的公共厕所管理系统,它要解决的核心问题可以拆成两个方向:

  • 用户侧:通过地图和列表快速找到附近开放的公共厕所,查看厕位的使用状态、评价信息、卫生情况,并可以对环境问题进行反馈。
  • 管理侧:保洁人员和管理人员通过小程序端或管理后台,记录保洁打卡、上报设施故障、统计人流数据,让公厕运维从"凭经验"变成"有数据"。

这个项目适合谁来参考?如果你是正在做课程设计、毕业设计的计算机相关专业学生,尤其是题目方向在"微信小程序 + Python后端"这一大类(比如校园服务、城市设施管理、生活类便民应用),这套系统的技术路线和工程组织方式可以直接借鉴。如果你是想入门 Flask 或小程序开发、想找一个完整项目练手的开发者,这篇文也会帮你少踩很多坑。

从技术角度来说,这个项目的技术栈并不复杂,但它的价值恰好在于那些"不复杂但容易出错"的细节——地理位置坐标的处理、小程序登录态的管理、图片上传的路径问题、列表分页加载的性能优化。这些细节单独看都是小问题,凑在一起就成了论文和答辩里最容易被追问的地方。下面我按实际开发顺序,把整套系统的设计思路、编码实现和部署踩坑记录拆开讲。

2. 技术选型的取舍:为什么是微信小程序 + Flask + Python

很多初学者拿到题目第一反应是"我要用最流行的技术",而不是"我要用最合适的技术"。这个项目在选型阶段,我其实对比过好几套方案,最终锁定微信小程序 + Flask + Python 组合,是经过实际权衡的,不是什么从众。

2.1 微信小程序:免安装、低门槛、与地图生态绑定

公共厕所的使用场景决定了它不适合做独立 App。你想一下,一个用户在外面急着找厕所,99% 的情况不会先去应用商店下载一个 App 再注册登录——这种低频刚需工具做独立客户端,获客成本高得离谱。微信小程序的"即用即走"模式天然适配这个场景,用户扫码或搜索就能打开,用完后随手关掉,不需要安装,也不涉及 iOS 和 Android 两套原生开发的工作量。

更关键的一点是,微信小程序内置了wx.getLocation和wx.chooseLocation等地理位置接口,配合腾讯地图的 JavaScript SDK,做"附近厕所搜索"这类 LBS 功能,比在原生 App 里申请定位权限、适配各种机型要省心得多。微信生态还提供了现成的登录体系(wx.login换取 openid),后端不需要自己再设计一套用户名密码注册流程。

2.2 Flask:轻量、贴近后端教学、适合快速迭代

后端选型我考虑过 Flask、Django 和 FastAPI。Django 功能最强,自带 Admin 后台和 ORM,但对这个项目来说有点重——我们需要的是一个能快速提供 JSON API 的轻量服务,不需要复杂的模板渲染和管理后台全套功能。FastAPI 性能好,但异步语法和类型标注对初学者不够友好,资料也没 Flask 丰富。

Flask 的优势在于:核心足够精简,一个 Python 文件就能启动服务;扩展生态成熟,SQLAlchemy 解决 ORM,Flask-CORS 解决跨域,Flask-JWT-Extended 解决登录态;学习曲线平缓,调试方便。对课程设计或毕业设计来说,Flask 的代码量更少,出问题时更容易定位,答辩时也更好讲清楚每个模块的原理。

2.3 前后端分离:不是所有项目都要上 Vue/React

项目采用了前后端分离架构——微信小程序只负责界面展示和用户交互,Flask 后端只提供 RESTful API,两者通过 JSON 数据交互。但要说清楚的是,这里的"前后端分离"并没有引入 Node.js 中间层或微服务,小程序端直接请求 Flask 服务,属于最简洁的分离方式。

为什么不加一层 Vue/React 管理后台?因为公厕管理系统的管理端功能相对简单——查看保洁记录、处理上报工单、统计厕所流量,用小程序本身的"管理角色页面"就能覆盖,不需要单独维护一套 Web 管理后台的代码。剪掉不必要的复杂度,这在工程实践里比叠加技术栈更重要。

2.4 数据存储:SQLite 起步,MySQL 上线

开发阶段我用的 SQLite,零配置、单文件、随拿随用,调试接口时特别方便。但考虑到项目要部署到云服务器,而且论文中需要体现"用户评价、保洁记录、上报工单"这类典型关系型数据模型,最终切到了 MySQL。切换过程比想象中顺利,因为 SQLAlchemy 的 ORM 层基本屏蔽了底层数据库差异,只需要改一个连接串。我的建议是:如果你也做类似项目,开发时 SQLite 完全够,但正式部署请务必换 MySQL,原因有两个——MySQL 的并发能力更强(尤其多人同时提交评价时),也更能应对答辩时"如果用户量大了怎么办"这类追问。

技术选型的表格总结如下,方便你做对比参考:

技术选型选择备选方案落选原因
前端微信小程序原生 App / H5 / uni-app低频刚需场景,小程序免安装门槛最低,地图组件最完善
后端框架Flask 2.xDjango / FastAPIDjango 过重,FastAPI 对初学者不够友好,Flask 简洁灵活
数据库MySQL 8.0SQLite / PostgreSQLSQLite 生产环境并发弱,PostgreSQL 相对小众,MySQL 运维资料最多
ORMSQLAlchemy 2.xraw SQL / peewee表结构变更可控,迁移方便,课堂上学过的直接用
地图服务腾讯位置服务高德 / 百度与小程序生态绑定好,API 申请简单,免费额度够用
部署云服务器 + Nginx + uWSGI微信云托管 / 宝塔面板传统部署可控性最强,也更适合写在论文部署章节

3. 后端 Flask API 的设计与实现

选定 Flask 作为后端框架之后,最难的部分不是"写接口",而是"设计接口的层次和协议"。很多初学者一上来就写@app.route('/getdata'),最后代码全堆在app.py里,一旦功能多一点就变成意大利面条。我的做法是先规划目录结构和数据模型,再写接口逻辑。

3.1 项目目录结构:按模块拆,而不是按文件拆

这个项目的后端最终是这样的目录结构:

server/ ├── app.py # 应用入口,注册蓝图 ├── config.py # 配置项:数据库、JWT密钥、上传目录 ├── requirements.txt # 依赖清单 ├── extensions.py # db实例、jwt实例(防止循环引用) ├── models/ │ ├── __init__.py │ ├── user.py # 用户表 │ ├── toilet.py # 厕所表 │ ├── review.py # 评价表 │ └── work_order.py # 工单表 ├── api/ │ ├── __init__.py # 蓝图注册 │ ├── auth.py # 登录/鉴权接口 │ ├── toilet.py # 厕所查询/详情接口 │ ├── review.py # 评价接口 │ ├── report.py # 问题上报接口 │ └── manage.py # 管理侧接口 └── utils/ ├── geo.py # 坐标系转换与距离计算 └── response.py # 统一响应格式

关键点是extensions.py单独拎出来——因为 Flask 的app = Flask(__name__)和db = SQLAlchemy(app)如果都写在app.py里,将来拆蓝图和数据模型时会产生循环导入问题。先把db、jwt这些扩展对象创建好,再在app.py里用init_app注入应用,这是 Flask 大型项目组织章节中必考的知识点。

3.2 核心数据模型:四张表就够用

公共厕所管理系统的主体数据模型是围绕"用户、厕所、状态、反馈"四个概念展开的。我设计了四张核心表和两张关联表:

  • User(用户):openid(小程序用户唯一标识)、nickname、avatar、role(普通用户/保洁员/管理员)。openid是微信生态的核心字段,后端不保存密码,只依赖微信身份系统。
  • Toilet(厕所):name、address、lat、lng(WGS-84坐标)、opening_hours、equipment(设施列表,如第三卫生间、无障碍通道)、status(正常/维护中)。坐标字段必须选对标准,这一点在第5章的踩坑记录里会重点说。
  • Review(评价):toilet_id、user_id、cleanliness_score(卫生评分1-5)、facility_score(设施评分)、content、image_urls、created_at。评价是用户端最重要的交互内容,后续列表排序会依赖它。
  • WorkOrder(工单):toilet_id、reporter_id、type(保洁/维修/耗材)、description、photo_url、status(待处理/处理中/已完成)、handler_id、handled_at。这是管理侧的闭环核心,保洁员或管理员看到工单后处理,处理完回填状态。

关联表和字段不复杂,但有个容易被忽视的点:所有时间字段都用created_at = db.Column(db.DateTime, default=datetime.utcnow),千万不要有多个 'status' 字段分布于不同表。统一字段命名规范,后续写统计 SQL(比如按天统计保洁完成率)会省很多事。

3.3 接口协议:统一返回格式与 JWT 鉴权

后端与小程序约定了一套统一的 JSON 响应格式,避免前后端各自定义返回结构。核心响应类在utils/response.py里定义:

  • 成功:{ "code": 0, "message": "success", "data": { ... } }
  • 业务失败:{ "code": 40001, "message": "具体原因", "data": null }
  • 未授权:{ "code": 401, "message": "token无效或过期", "data": null }

登录态用flask-jwt-extended实现。流程是:小程序端wx.login拿到临时的code,传给后端;后端拿code调用微信的code2Session接口换取openid;服务端根据openid查找或创建用户,签发 JWT token 返回给小程序;后续请求在请求头带上Authorization: Bearer <token>,用@jwt_required()装饰器保护需要登录的接口。

这里有一个我在项目里吃过大亏的细节:不要在每次请求里都调用微信接口换openid。wx.login的code是一次性的,用code换取的openid才是长期标识。正确做法是登录成功后就把openid作为用户唯一标识存库,后续所有鉴权都基于 JWT token,与微信服务器无关。

3.4 附近厕所搜索的 LBS 实现

"附近厕所"是这个系统最核心的功能,后端接口设计为:

GET /api/toilet/nearby?lat=xx&lng=xx&radius=2000

返回以用户当前位置为圆心、radius米范围内的所有厕所,按距离升序排列。实现方式有两种:

方式一:SQL 实时计算(适合数据量少于几千条)

SELECT id, name, lat, lng, 6371000 * acos( cos(radians(%(lat)s)) * cos(radians(lat)) * cos(radians(lng) - radians(%(lng)s)) + sin(radians(%(lat)s)) * sin(radians(lat)) ) AS distance FROM toilet HAVING distance < %(radius)s ORDER BY distance;

这个公式本质是 Haversine 公式,把经纬度换算成球面距离,需要把用户坐标作为参数传入。优点是精度尚可、实现简单,缺点是数据量大时全表扫描太慢。但这个项目体量的数据量(全国城市公厕数据量撑死几千条)完全扛得住。

方式二:Geohash 网格(适合数据量大或需要性能优化)

utils/geo.py里实现了一个简化的 geohash 编码器,将经纬度映射为字符串,查询时先按 geohash 前缀粗筛候选集,再在候选集内计算精确距离。我用 6 位 geohash(约 0.6 公里×0.6 公里的网格),可以显著缩小扫描范围。

对于论文或答辩来说,两种方式都写进去,并解释清楚"数据量小时全表 SQL 足够,数据量大到百万级再考虑 geohash 分桶",是非常加分的点。

3.5 评价与上报接口设计

评价接口是用户主动提交内容的入口:

POST /api/review/submit Body: { "toilet_id": 2, "cleanliness_score": 4, "facility_score": 5, "content": "很干净", "image_urls": [...] }

需要注意三点。第一,接口要做数据校验,分数必须在 1-5 之间,内容长度 < 500 字符,图片列表最多 3 张。第二,同一用户 24 小时内对同一厕所的重复评价应该被拦截,防止刷屏——最简单的实现是查询created_at和user_id、toilet_id联合查询。第三,评价后需要更新厕所表的avg_cleanliness、review_count字段,这属于典型的写操作顺序问题,我放在后面并发部分详述。

工单上报接口类似,传入type、description、photo_url,创建时status默认为 "pending"。管理侧接口(如工单列表、统计报表)会被@jwt_required()+ 自定义@admin_required装饰器保护,避免普通用户越权操作。

4. 微信小程序前端的开发细节

后端把 API 设计好后,前端小程序的工作重心是页面组织、交互体验和与地图组件的集成。小程序虽然号称"开发简单",但真正上手你会遇到很多官方文档没写透的细节。

4.1 页面结构与底部导航

项目采用经典的三 Tab 结构:

  • 首页(地图模式):整页显示地图,标记附近的厕所,点击标记弹出卡片,可以跳转导航或查看详情。这个是"找厕所"的核心入口。
  • 列表页(列表模式):以列表形式展示附近厕所,支持下拉刷新、触底加载更多,每条展示名称、距离、评分、当前状态。
  • 我的(个人中心):展示用户信息、我的评价记录、问题上报记录,管理角色额外显示"工单处理"入口。

单页模式和多 Tab 模式的选择上,我觉得公厕场景不适合"先列表后详情"的传统导航,用户更需要"打开就知道哪里有厕所"——所以首页直接放地图,列表切换通过页面顶部的选项卡完成,而不是独立 Tab。

4.2 地图组件的接入与定位权限

小程序端地图方案选用腾讯位置服务,在小程序后台配置域名白名单后才能正常请求。

核心步骤:

  1. 在小程序app.json里配置"permission": { "scope.userLocation": { "desc": "用于查找附近公共厕所" } }。
  2. 页面onLoad时调用wx.getLocation({ type: 'gcj02' })。这一步的关键是type参数——小程序的wx.getLocation返回的是GCJ-02 坐标(国测局坐标),而如果你用的地图 SDK 或后端存储的数据是 WGS-84(GPS 原始坐标),两者之间会有几十到几百米的偏移,必须做坐标系转换。我在第5章会详细展开。
  3. 拿到坐标后通过wx.request请求后端nearby接口,返回厕所列表后,用地图组件的markers属性批量渲染标记点。

地图标记点的callout可以显示厕所名称和评分,但注意callout不支持自定义样式,只能在原生 CSS 范围内调整。如果想让卡片更好看,可以做一个自定义 view 叠在 map 上面的方案——通过cover-view实现。这个细节值得写进你的踩坑笔记。

4.3 列表加载更多与下拉刷新

列表页是数据量最集中、性能问题最容易暴露的地方。结合网络热搜词里的"微信小程序页面列表加载更多",这个功能的实现方案已经比较成熟,但有两个坑必须自己踩过才知道。

坑一:onReachBottomDistance的值不是绝对的。它表示距离页面底部多少距离时触发onReachBottom,但这个距离在不同机型上的表现并不一致,建议设 50-100px 配合节流逻辑使用。

坑二:分页参数要统一。我用page和page_size做分页,page从 1 开始,触底时page += 1。后端返回{ list, total, has_more },每次请求结束后要判断has_more决定是否加载"没有更多了"的提示。

// 加载更多示例 loadMore() { if (this.data.loading || !this.data.hasMore) return; this.setData({ loading: true }); let page = this.data.page + 1; wx.request({ url: `${BASE_URL}/api/toilet/nearby`, data: { lat, lng, page, page_size: 20 }, success: (res) => { const list = res.data.data.list; this.setData({ list: this.data.list.concat(list), page, hasMore: res.data.data.has_more, loading: false }); } }); }

触底加载最容易被忽视的一点是"防止重复请求"——用户快速滚动时onReachBottom可能被触发多次,初始化时设置loading = true加上函数体开头的if (this.data.loading) return就能拦截掉。另外问一句:页面数据会不会出现在内存里只增不减?如果列表比较长,使用recycle-view(可回收列表)更稳妥,小程序长列表的性能优化题答这里非常加分。

4.4 从 wx.request 到真实数据联调

开发阶段最容易遇到的就是「请求发出去了、数据也没问题,但显示不出来」。我的排错顺序是:

  1. 确认请求 URL 是否合法。小程序要求所有请求必须是 HTTPS(开发工具可以勾选"不校验合法域名"),部署到真机后不走这个豁免,域名必须是备案过的 HTTPS。
  2. 确认后端是否配置了 CORS。小程序wx.request是基于 XMLHttpRequest 的,跨域时 Flask 后端必须用flask-cors设置CORS(app),否则请求会被浏览器同源策略拦截。
  3. 确认 JSON 数据格式是否一致。我在utils/response.py统一了code、message、data结构,小程序端做一个parseResponse函数统一解析,避免每个页面重复写错误处理。

联调时建议打开小程序开发者工具的"不校验合法域名"选项,但真机预览时必须关闭——这是我曾经在答辩前两天才发现的坑,差点因为他翻车。

5. 部署上线与真实踩坑记录

如果这篇文章只能留下一部分,我希望是这一章。因为系统开发中踩过的坑,才是别人在文档里看不到的、最能体现经验价值的地方。

5.1 部署方案:Nginx + uWSGI + Flask

后端部署没有直接用flask run,而是采用了uWSGI + Nginx 反向代理的组合。原因也简单:flask run自带的开发服务器既不够稳,也不适合并发场景,更没法通过 80/443 端口直接对外提供服务。部署流程梳理如下:

  1. 用pipenv install生成requirements.txt,在干净的云服务器上创建虚拟环境并安装依赖。
  2. 配置 uWSGI,核心配置如下:
[uwsgi] http-socket = 127.0.0.1:5000 processes = 4 threads = 2 master = true chdir = /var/www/server module = app:app vacuum = true die-on-term = true
  1. 配置 Nginx 反向代理,将/api路径转发到127.0.0.1:5000,同时做静态文件的直接放行。

  2. 开放 443 端口并配置 HTTPS。微信小程序后台要求配置域名时必须填 HTTPS 地址,而且必须有有效的 SSL 证书。用 certbot 申请 Let's Encrypt 免费的 SSL 证书就行,注意 Nginx 的配置里要加上 HTTP 跳转。

5.2 小程序域名与 HTTPS 配置:绕不开的流程

真机测试时小程序请求后端接口,必须在「微信公众平台-开发管理-服务器域名」里把 request 合法域名和 uploadFile 合法域名都配上。注意三个细节:

  • 域名必须已经 ICP 备案,这是硬性要求,没有备案号的域名提交不下白名单。
  • request合法域名最多配 20 个,uploadFile合法域名是独立的配置项,图片上传必须单独配。
  • 如果调试时临时用了 IP 地址或本地地址,真机上 100% 会失败,必须在开发者工具里都把地址替换为正式域名。

这个坑耗费了我将近一整天:开发时全部用http://127.0.0.1:5000调通了,真机预览白屏,控制台给一个"不在合法域名列表中"的错误。后来才发现微信开发者工具真机预览时,请求地址必须是已备案、已配置为 HTTPS 的正式域名,没有捷径可走。

5.3 踩坑实录一:坐标系偏移,地图上的厕所全都"飘"了

这是整个项目中隐藏最深、最容易在答辩时被问到的一个问题。微信小程序的wx.getLocation默认返回 GCJ-02 坐标系(俗称国测局火星坐标),而我们在后端数据库里存的厕所经纬度,最初是用手机 GPS 测试生成的,属于 WGS-84 坐标系。两者坐标方向偏移了约数百米,结果就是地图标记出的厕所位置与真实建筑偏差巨大。

排查全过程是:

  1. 先用地图组件实测,发现标记点位置和真实点位置大约相差 300 米,而且偏移方向不固定。
  2. 查资料确认是坐标系标准差异,在小程序端wx.getLocation里改了type: 'gcj02',地图是基于腾讯地图的,等于反过来绕了一圈。
  3. 真正合理的处理是在后端统一将存储坐标转换为 GCJ-02(因为腾讯地图使用 GCJ-02,前端直接消费),并顺手写了utils/geo.py里的wgs84_to_gcj02坐标转换函数。

如果你要复现这个问题,可以直接在代码中把 WGS-84 坐标往地图上丢,马上看到偏移。但这个坑最本质的原因是"坐标系不统一",无论是珠海、诺瓦的坐标体系,还是 GCJ-02、WGS-84、BD-09,都要在项目设计时写清楚"全项目统一使用哪套坐标系",这句话写进论文,答辩老师会觉得你想清楚了。

这个案例特别适合写进论文的"系统测试"或"问题处理"章节,既真实又可验证。

5.4 踩坑实录二:并发写入时评价与平均值不一致

用户提交评价后,后端需要同时做两件事:写评价记录 + 更新厕所的avg_cleanliness、review_count。如果两个操作之间不做事务控制,并发提交时可能出现"评价记录写进去了,平均值没更新"或者"平均值更新了但两次计数重复"的情况。

我的第一版代码是这样的:

review = Review(**payload) db.session.add(review) db.session.commit() # 先提交评价 # 再更新厕所统计 toilet = Toilet.query.get(toilet_id) toilet.review_count += 1 toilet.avg_cleanliness = (toilet.avg_cleanliness * (toilet.review_count - 1) + score) / toilet.review_count db.session.commit()

并发请求一多就出问题。两个用户同时提交时,第一个 commit 还没结束,第二个已经读到旧的review_count,更新互相覆盖。修复方式是使用事务加行级锁:

try: db.session.begin() # 使用 with_for_update 锁定厕所行 toilet = Toilet.query.filter_by(id=toilet_id).with_for_update().first() review = Review(**payload) db.session.add(review) toilet.review_count += 1 toilet.avg_cleanliness = round( (toilet.avg_cleanliness * (toilet.review_count - 1) + score) / toilet.review_count, 1 ) db.session.commit() except SQLAlchemyError: db.session.rollback()

MySQL 的SELECT ... FOR UPDATE保证同一时间只有一个事务能修改该厕所行的统计字段,彻底避免了竞态问题。类似的问题还会出现在保洁打卡签到(同一个人重复打卡)、工单状态流转(处理中不能再被关闭),建议在论文的并发控制小节一并提及。

5.5 踩坑实录三:图片上传后的路径与访问权限

当时用户反馈"上传的厕所照片时好时坏",在服务端排查发现:图片上传的临时目录在自己找的/tmp/upload下,Nginx 直接访问不到;另外,用werkzeug.utils的secure_filename处理中文文件名时,返回的全是下划线,图片名在数据库里和要访问的路径对不上。

最终方案:

  • 图片保存目录放在/var/www/server/uploads/下,按日期分目录,文件名用uuid4().hex + 后缀重新生成,彻底摆脱中文问题。
  • Nginx 配置一个/uploads静态路由指向该目录。
  • 小程序端上传用wx.uploadFile,必须配置 uploadFile 合法域名,和 request 域名是独立的。

这个坑提醒我:上传的文件路径必须遵循"程序生成什么,物理路径就存什么"的统一规则,而不要依赖用户的原始文件名。

6. 论文视角:把工程实践转化为研究内容

6.1 论文框架怎么搭

这个项目做出来以后,把材料整理成毕业论文并不难。我的整体章节结构供你参考:

  • 第一章 绪论:研究背景(城市公厕管理问题)、研究意义(提升使用体验和管理效率)、国内外研究现状(重点写"物联网+公厕"的进展,以及传统台账管理的痛点)、论文组织结构。
  • 第二章 相关技术简介:微信小程序、Flask、Python、SQLAlchemy、LBS、JWT。注意这一章不是抄百度百科,而是要写"为什么选这个技术、它在本系统中承担什么角色"。
  • 第三章 系统分析:需求分析(用户、保洁员、管理员三视角)、可行性分析、功能模块划分、用例图。
  • 第四章 系统设计:总体架构、数据库设计(ER 图 + 表结构定义)、接口设计(列出所有 API 及参数)。
  • 第五章 系统实现:各功能模块的关键代码截图 + 逻辑讲解,要避免整段贴代码,核心逻辑可以用流程图或文字描述。
  • 第六章 系统测试:功能性测试用例表、性能测试(并发请求响应时间)、兼容性测试(不同微信版本)。
  • 第七章 总结与展望:总结工作、指出不足(如数据量不足、AI 辅助管理未实现)、未来方向(智能推荐、人流热力图、AI 识别臭味)。

答辩老师最常问的三个问题是:"为什么用 Flask?"、"数据库表为什么这样设计?"、"如果没有微信小程序,你会怎么做?"——前两个用第2、3章的内容直接回答即可,第三个问题要预先准备好逻辑:"用 Android 原生 / Web H5 替代,但需要处理多端适配,小程序是最优解。"

6.2 数据与验证章节的写作技巧

论文里"系统测试"章节最容易被写成流水账。我的建议是:每个功能模块配一个简单的表格,列出"测试用例、输入数据、预期结果、实际结果、是否通过",三到五个模块就够了。性能测试部分,可以用 APT 或 Postman 的 Collection Runner 压一下接口,记录响应时间和吞吐量,画两张折线图,论文的实证感直接拉满。

如果你做到这一步,会发现一个加分项:收集真实用户反馈数据。可以像网络热搜里说的那样,"微信开发者工具里的小程序怎么发给其他人试用收集几天的试用反馈"——通过体验版二维码发给同学帮忙测试,记录他们提交的几十条评价和工单数据作为论文示例,比纯造数据有说服力得多。

6.3 从系统演示到答辩准备的注意事项

答辩演示环节,我建议准备一个"演示脚本":明确第一步展示什么、第二步展示什么,不要现场操作太长时间。核心演示序列可以是:

  1. 登录(展示微信授权流程)
  2. 首页地图定位 + 附近厕所展示(现场改坐标显示不同区域)
  3. 查看厕所详情 + 提交评价
  4. 上报工单 + 管理端处理工单
  5. 后端数据库同步变化的直观展示(用一个 SQL 查询在当前终端里把新记录打印出来)

还有两个细节:第一,现场演示前一定要切换为真机预览,开发工具里的模拟器和真机定位差异很大;第二,提前关掉所有无关终端窗口,只保留需要展示的后端日志,避免现场输出太长干扰注意力。

我当年答辩的时候,所在小组三个人,剩下两个人一个演示到一半 token 过期重新扫码浪费了两分钟,另一个是地图空白页面在加载状态卡住。所以"演示流程跑通 + 边界情况提前想好"真的不是废话。我个人建议你真机演示,而不是截图演示——老师更想看到你亲手跑起来一遍,截图会引发"不会是真机没通过吧"的怀疑。

7. 项目复盘:如果再让我做一次,我会怎么改

这个项目做完已经跑通全流程,真机测试、腾讯云部署、论文提交都完成之后,回过头看仍然有几个地方可以做优化:

第一个是引入 WebSocket 实时推送。目前工单状态更新后,保洁员或管理员必须手动刷新列表才能看到新工单。如果引入 WebSocket(比如 Flask-SocketIO),可以在服务端主动推送"新工单到了"的消息,体验会好很多。不过这会增加部署复杂度,并且和传统的 HTTP 请求模型不好兼容,考虑到系统体量,我最终没做。

第二个是加入 AI 图像识别做卫生状况判断。用户上报工单时上传的照片包含大量有效信息。如果接入云厂商的通用图像识别接口,可以自动判断"地面是否湿润""是否有明显垃圾",然后对工单紧急程度做自动分级。这块如果作为毕业设计的方向,会被老师认为是很好的创新点,也是目前城市管理智能化的大趋势。不过要合理估计成本和时间,AI 接口的接入和调优闭环并不轻松。

第三个是更完善的权限矩阵。我用role字段区分普通用户、保洁员和管理员,但实际业务中"保洁员可能只管理特定片区的厕所""管理员可能只管某个街道的公厕",这种细粒度的权限控制没有完全做。如果数据规模进一步扩大,需要引入"角色-资源"关联表,不然后台一多就乱套。

这些没有做的功能,并不是失败,它们恰好是论文最后一章"展望"里最好的素材。在答辩和论文中,坦诚"目前系统实现了核心流程,但还有这些方面可以进一步优化",比试图把所有功能都堆上去更得体,也更能反映你对系统边界的思考。你要明白,产品做到 80 分就具备工程交付价值了,剩下的 20 分留给未来的迭代,这是真实项目的常态。

最后再分享一个小技巧:做完整个项目,一定要把所有核心配置项(数据库连接、JWT 密钥、上传目录)都集中放在config.py里,并把真正的密钥放在环境变量中而不是写死在代码里。答辩时如果老师问"你的系统安全怎么做的",你至少能说出"配置分离、密钥不硬编码、接口走 JWT 鉴权"这三点,比只会说"有密码登录"强得多。这不仅是项目收尾的体面,也是你从学生思维转向工程思维的第一步。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询