在校园里,自习室座位紧张是每个学期末的保留节目。占座、抢座、去了发现没位置,这套循环往复的糟心事,几乎所有学生都经历过。我前阵子给学校信息中心做了一个基于微信小程序的校园自习室预约系统,前端用 uniapp,后端用 Python,整体跑下来效果不错,已经稳定运行了一个学期。今天就把这套系统的完整设计和实现过程拆开讲一遍,从技术选型到数据库设计,从页面适配到打包上线,把能踩的坑和解决思路都写出来,给准备做类似项目的同学和同行一个参考。
1. 项目定位与方案选型
1.1 核心需求拆解
做这个系统之前,我先和图书馆、教务处的老师聊了几轮,把真实痛点捋清楚了。
自习室场景最核心的需求其实就四个:查座位、约座位、签到、释放。学生端要能看到哪个自习室有空位、哪些座位被占用,能够在线预约一个时间段,到现场之后签到确认,离开时释放座位。管理端要能维护自习室和座位信息、查看预约记录、处理违规占座。
需求听起来简单,但实际做的时候有几个隐形坑。一是座位状态必须实时准确,这个直接关系到学生体验,显示有座但去了发现被占,一次就能让学生弃用;二是预约规则要灵活,比如高峰期限时、非高峰期不限时,不同时间段策略不同;三是微信小程序的登录、订阅消息推送、定位签到这些能力都要接好,任何一个环节出问题都会被投诉。我把需求细化成功能清单之后才动工的,强烈建议你们做同类项目也别上来就写代码,先把需求文档写清楚。
1.2 技术栈选型逻辑:uniapp + Python
技术选型是我最先定下来的事。前端选了 uniapp,后端选了 Python。
为什么前端用 uniapp?最直接的理由是跨端。虽然项目标题叫“微信小程序”,但学校方面明确提过:以后可能要做 App、要做 H5 版,甚至要接入企业微信。如果用原生小程序开发,将来每一端都得重新写一套;uniapp 的语法基于 Vue,写一套代码可以同时编译到微信小程序、App、H5 等多个平台,切换成本低很多。另外 uniapp 的社区生态成熟,uview-plus 这类组件库拿来即用,对于没有专门前端团队的信息中心来说,维护起来压力小。
Python 后端这边,我用了 FastAPI。理由有三点:第一,FastAPI 自带 OpenAPI 文档,接口写完自动生成可视化文档,联调的时候给前端和第三方对接都省事;第二,基于 Pydantic 的请求体校验很舒服,前端传参不规范会被直接拦截,不至于让脏数据流到数据库;第三,异步支持好,自习室预约在高峰期会频繁查询座位状态,能异步处理意味着更高并发。框架重不重要?在快节奏落地的项目里,要么选自己最熟的,要么选生态最成熟的,别为了炫技选冷门框架。
Python 环境安装本身没什么好说的,官网下载对应版本装好就行。建议装 3.8 以上版本,我用的 3.10,FastAPI 和 SQLAlchemy 的兼容性都很好。我踩过的唯一一个环境坑是:win 系统下 pip 安装某些依赖包会失败,比如 pydantic-core,这个时候降到 Python 3.9 或者直接装预编译 wheel 就能解决。
1.3 服务架构:小程序 + 后端 + 数据库
整套系统的架构很直接:微信小程序端(uniapp 编译产物)通过 HTTPS 请求 Python 后端,后端负责业务逻辑和数据库读写,数据库用 MySQL。Redis 用来做座位状态的缓存和热点数据的临时存储。为什么不全部用 MySQL 存?因为座位状态的查询频率实在太高了,每次都去查数据库,数据库压力大、响应也会慢。我用 Redis 存座位当前状态,用 MySQL 存预约记录的永久数据,二者配合。实测高峰期接口响应稳定在 200ms 以内。
微信侧的配置也要提前想清楚。小程序需要 AppID 才能用完整能力,登录用的是微信的 code 换 openid 机制,订阅消息需要在小程序后台申请模板。这些都要提前准备,别等开发到一半发现缺资质。
2. 数据库设计与核心接口定义
2.1 数据表设计详解
数据库设计是整个系统的地基。自习室预约系统的核心表有这几张:用户表、自习室表、座位表、预约记录表、签到记录表、违规记录表。
用户表主要存微信用户的基础信息,包括 openid、昵称、头像、学号、身份类型。openid 是用户在小程序体系里的唯一标识,后端就靠它来识别用户身份。学号是后来做学生认证加的,因为学校要求实名预约。
自习室表存自习室名称、楼层、开放时间、容量、状态。座位表比较关键,每一条记录对应一个物理座位,需要关联自习室 id,还要有座位编号和位置描述,比如“A区 3排 05号”,方便学生到现场找座位。座位表必须有个特殊字段来标记座位状态,但注意:座位状态这种高频变动数据,实际查询用的是 Redis,MySQL 里的状态只做恢复用,这个设计让我避免了很多锁竞争的问题。
预约记录表是核心中的核心,字段包括预约单号、用户 id、自习室 id、座位 id、预约日期、开始时间、结束时间、状态。状态我设计了几个取值:待签到、已签到、已完成、已取消、违规释放。这里要特别说下预约单号怎么生成,我用了 日期+自习室编号+随机四位 的方式,不要用自增 id 当预约单号展示给学生,容易暴露业务量,也没必要。
签到记录表单独建出来是为了后续统计。哪些人到场了、多少人鸽子了、哪些座位使用率低,这张表都能查出来。很多团队项目做到后面才补统计功能,结果发现原始数据没记全,补都没法补。所以签到这种关键行为,一定要单独落表。
2.2 接口清单与请求设计范本
接口设计我遵循一个原则:小程序端尽量简单,复杂逻辑后端正。前端只负责展示数据和收集用户操作,不要在后端之外写太多业务规则。
核心接口大概这些:
POST /api/auth/login微信登录,传 code,返回 token 和用户信息GET /api/rooms获取自习室列表,附带每个自习室的实时空位数GET /api/rooms/{id}/seats获取某自习室的座位状态列表POST /api/reservations提交预约,传座位 id、时间段POST /api/reservations/{id}/checkin签到,会校验定位POST /api/reservations/{id}/release释放座位GET /api/reservations/my查询我的预约记录GET /api/admin/stats管理端统计
我拿POST /api/reservations举个例子。请求体会带 seat_id、start_time、end_time。后端先校验用户身份,再校验时间段的合法性,然后查 Redis 确认座位在这个时间段是空闲的,用事务写入预约记录,同时更新 Redis 座位状态。整个流程加了乐观锁,避免两个人同时预约同一个座位。一开始我不加锁,测试时拿两台设备同时点,还真复现了双人约上同一座位的问题,后来在座位状态更新时加了版本号判断,问题解决。
2.3 为什么座位状态要用 Redis 管理
自习室座位状态的查询请求量特别大。高峰期可能有几百个学生同时刷新座位列表,如果每个请求都直接查数据库,MySQL 的连接池很可能被打满,接口延迟会飙升。我把座位状态放到 Redis 里之后,情况好了很多。
具体做法是:每个座位在 Redis 里存一个 key,比如seat:status:10086,value 是 0 或 1,1 表示已占用。查询列表时用 pipeline 批量读取所有座位状态,几百个 key 一次请求就能拿到。预约成功或者释放座位时,更新对应 key。为了防止 Redis 和 MySQL 数据不一致,我加了一个定时任务,每小时把 Redis 的座位状态全量同步回 MySQL,同时在服务重启时从 MySQL 恢复 Redis。这套方案在并发 200+ 的测试下没有出现状态错乱。
3. uniapp 前端开发实战
3.1 项目初始化与 uview-plus 集成
uniapp 项目创建我用的 HBuilderX 可视化创建,选 Vue3 版本,模板就自带的默认模板。创建好之后第一件事就是引入 uview-plus,这个组件库提供了大量现成的 UI 组件和工具函数。
集成 uview-plus 有几步关键操作。首先要在插件市场导入,可以手动导入插件 zip 包也可以直接用 HBuilderX 的插件市场安装。然后要在main.js注册:import uviewPlus from 'uview-plus'并app.use(uviewPlus)。之后在uni.scss里引入主题文件,在App.vue里引入基础样式。
这里有个坑必须提醒一下:uview-plus 的版本非常关键。如果你是 Vue3 项目,必须用 uview-plus 而非 uview 2.x,uview 2.x 只支持 Vue2,装错版本会直接白屏报错。我最初没注意,把 uview 当 uview-plus 装进去,页面全空白,控制台报模块找不到,排查了大半天。
集成完成后,我就开始搭底部导航栏和页面结构。TabBar 我配了三个页面:首页(自习室列表)、预约记录、我的。另外还有几个非 Tab 页面,如自习室详情、座位选择、签到页、管理端页面。
3.2 登录、用户信息与鉴权
微信小程序的登录流程是:前端调用uni.login获取 code,传给后端,后端拿 code 去微信接口换 openid,然后生成自己的 token 返回给前端。
代码大概是这样的:
// 前端登录 uni.login({ provider: 'weixin', success: async (loginRes) => { const res = await request.post('/api/auth/login', { code: loginRes.code }) uni.setStorageSync('token', res.data.token) uni.setStorageSync('userInfo', res.data.userInfo) } })我前端封装了一个request.js,基地址从环境变量读,开发环境指向本地局域网 IP + 端口,测试环境指向测试服务器。每次请求会自动带上 token,后端通过 token 识别用户身份。封装请求拦截器和响应拦截器是很必要的,统一处理 401 状态、网络错误和业务错误码,避免每个页面都写一堆重复的错误处理代码。
登录态过期也是小程序里常见问题。我做了 401 拦截后自动重新登录的重试机制,保证用户无感知刷新 token,体验会顺滑很多。
3.3 自习室列表与加载更多翻页
自习室列表页是用户进入系统看到的第一个页面,做得好不好直接影响第一印象。这个页面的核心是卡片式布局展示每个自习室的信息:名称、楼层、当前空位数、开放时间、距离。
数据加载用到了分页。热搜词里的“微信小程序页面列表加载更多”就是这个场景的核心。uniapp 中实现滚动加载有两种方式:一种是onReachBottom页面生命周期钩子,另一种是 scroll-view 的@scrolltolower。列表页一般用前者就行。
onReachBottom() { if (this.hasMore && !this.loading) { this.pageIndex += 1 this.loadRoomList() } }每次加载完数据要判断返回的数据条数是否小于每页条数,如果小于说明没有更多了,hasMore置为 false,页面上就显示“没有更多了”的提示。加载状态必须控制好,避免重复请求。
我实测下来的经验是:每次进入页面时,要刷新第一页数据。小程序页面有缓存,用户可能在其他页面操作后回来,列表数据可能已经变了。我在首页的onShow钩子中重新加载列表,保证数据实时性。
3.4 小程序顶部导航栏的高度适配与自定义导航
项目里有几个页面用了自定义导航栏,因为要放自定义按钮。这里就绕不开“微信小程序顶部导航栏高度”这个高频问题。
顶部导航栏的组成是两部分:状态栏高度 + 导航栏高度。状态栏高度可以通过uni.getSystemInfoSync().statusBarHeight获取,导航栏高度在胶囊按钮出现后一般固定是 44px,但如果用自定义导航栏,就得动态计算胶囊按钮的位置。
我封装了一个工具函数:
export function getNavBarHeight() { const systemInfo = uni.getSystemInfoSync() const menuButton = uni.getMenuButtonBoundingClientRect() const statusBarHeight = systemInfo.statusBarHeight const navBarHeight = (menuButton.top - statusBarHeight) * 2 + menuButton.height return { statusBarHeight, navBarHeight, menuButton } }这个计算逻辑的原理是:胶囊按钮垂直居中于导航栏,所以导航栏高度等于(胶囊顶部到状态栏底部的距离)*2 + 胶囊高度。不同机型上这个值会略有不同,别写死 44px。写死的话,iPhone X 系列和 Android 全面屏手机都会错位。导航栏的高度问题不用自己查很久,直接用这个公式一劳永逸。
3.5 预约选座的交互设计
选座交互是前端最核心的页面。我把自习室座位图用网格布局展示,每个座位是一个小方块,三种颜色表示三种状态:绿色空位、红色已占、灰色不可用。
小方块是可点击的,点击后弹出时间选择组件,默认是当前时间段往后 2 小时,也可以自定义。提交预约后调用后端接口,成功后把座位的颜色立即改成红色,同时做一个简单的动画反馈。
这里要提到一个体验细节:选座时如果座位被其他人抢先预约了,后端会返回“座位已被预约”的错误。前端要捕获这个错误,并刷新座位状态。我最初没有处理这个分支,结果用户点击“已被抢”的座位,界面毫无反应,非常困惑。后来加了 toast 提示和状态刷新,体验好了很多。
3.6 日志调试与发布设置
调试阶段有一个很多开发者都会犯的错:在 uniapp 中写了很多console.log,结果在微信开发者工具里看不到输出。热搜词里的“uniapp 不打印日志信息”说的就是这个问题。
原因很简单:uniapp 编译到微信小程序,console.log 会保留,但如果你开了“过滤”或者日志级别设置不对,可能就看不到了。另外,你的代码如果被压缩混淆了,某些 console 日志会被移除,特别是打包发布版本。
我的经验是:开发阶段在 HBuilderX 中运行到微信开发者工具时,先在 HBuilderX 控制台确认构建有没有报错,在微信开发者工具控制台把日志级别设置为“All”,并且确保没有开启“Cache”模式。如果还是看不到,可以强制清缓存再编译一次。还有一个技巧是使用console.log的替代方案,比如 uni-app 的uni.showToast,或者封装一个 logger 函数,在开发环境输出调试信息,生产环境直接静默,这样既不会影响调试也不会泄漏内部信息。
HBuilderX 中运行到小程序,需要在manifest.json的“微信小程序配置”里填上你的 AppID。如果没填,微信开发者工具会提示使用测试号。真想调试完整版功能,AppID 必须是真的。
4. Python 后端开发与接口实现
4.1 FastAPI 项目结构
后端项目目录结构我按模块化拆分,没有全部堆在几个文件里。结构大致是:
app/ main.py # 入口 config.py # 配置 database.py # 数据库连接 models/ # ORM模型 schemas/ # Pydantic响应模型 routers/ # 路由 services/ # 业务逻辑 utils/ # 工具函数这样分层的好处是职责清晰:路由层只管接收请求、返回响应;服务层才是业务逻辑的核心;模型层只定义数据表结构。新人接手项目时,按这个目录能很快找到对应代码。我见过不少项目把接口逻辑全写在main.py里,一两千行下来几乎没法维护。
4.2 微信登录接口的完整实现
微信登录接口是用户接触到的第一个后端接口。流程上,前端传code给我,我用 code 去微信的jscode2session接口换取 openid 和 session_key。这里要特别说明:session_key 永远不能下发到前端,也不能入库,它只在需要解密用户信息时才会用到。
@app.post("/api/auth/login") async def login(req: LoginRequest, db: Session = Depends(get_db)): url = "https://api.weixin.qq.com/sns/jscode2session" params = { "appid": settings.WX_APPID, "secret": settings.WX_SECRET, "js_code": req.code, "grant_type": "authorization_code" } async with httpx.AsyncClient() as client: resp = await client.get(url, params=params) data = resp.json() if "errcode" in data: raise HTTPException(status_code=400, detail="微信登录失败") openid = data["openid"] user = db.query(User).filter(User.openid == openid).first() if not user: user = User(openid=openid) db.add(user) db.commit() token = create_access_token(user.id) return {"token": token, "user": {"id": user.id, "nickname": user.nickname}}重点是:首次登录自动注册用户,之后登录直接走 token 签发,不需要重复注册。token 我用的是 JWT,设置了 7 天有效期。JWT 的好处是无状态,后端不用存 session,对多实例部署也友好。
4.3 预约接口的并发控制
预约接口是整个系统最复杂的接口。它要检查很多东西:用户是否认证、自习室是否开放、座位是否存在、时间段是否合法、座位是否空闲、用户是否有未完成的预约。
最关键的一步是并发控制。我用的是 Redis 的 SETNX 命令,对座位加锁。具体的实现方式是这样的:
lock_key = f"seat:lock:{seat_id}:{start_time}:{end_time}" locked = redis_client.set(lock_key, "1", nx=True, ex=60) if not locked: raise HTTPException(status_code=409, detail="座位刚被别人预约了,请重新选择")加了这把锁之后,同样座位同时段的重复预约就只能放行一个。这个锁必须有超时时间,不然用户请求中途崩溃,锁会一直占着,导致该座位永远不能预约。我还做了事务回滚,如果预约创建失败就删除锁,保证现场干净。
4.4 定位签到实现及其注意事项
签到功能学校明确要求要做,目的是防止“人不去但预约了”的放鸽子行为。我实现的方式是:前端通过uni.getLocation获取经纬度,传给后端,后端计算这个经纬度是否在自习室所在楼栋的一定范围内(比如半径 200 米)。
代码大概这样:
from math import radians, cos, sin, asin, sqrt def haversine(lon1, lat1, lon2, lat2): R = 6371000 dlon = radians(lon2 - lon1) dlat = radians(lat2 - lat1) a = sin(dlat/2)**2 + cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon/2)**2 return 2 * R * asin(sqrt(a))如果计算出的距离超过阈值,就拒绝签到。这里有个实际的坑:校园内 GPS 定位精度有时很差,误差可能到几百米,尤其是在室内。所以阈值不能设得太死,我设了 300 米,同时提供“手动签到”的管理端入口,遇到定位失败的学生可以找管理员处理。硬要卡死距离定位,会让真实用户觉得很烦,体验反而不好。
签到成功之后要同步调微信订阅消息,给用户推一条“签到成功”的通知。订阅消息模板需要在小程序后台申请,审核过了才能调用。这个也是提前准备的事项。
4.5 numpy 与量化策略等热搜词的无关联想
热搜词里有一堆 python 学习、numpy 安装、量化交易策略之类的词,跟自习室预约没有直接关系。但可以顺嘴提一句:Python 生态很庞大,不同方向用到的库完全不同。做后端开发用 FastAPI、SQLAlchemy 这类库;做数据分析才需要 numpy、pandas。别一上来就全装一遍环境,缺什么装什么,环境才能保持干净。我本人做项目宁可新建一个虚拟环境,也不用全局环境,python -m venv venv一行命令就能隔离依赖,省得后面一堆版本冲突。
5. 调试、打包与会话保持的实战经验
5.1 使用 Charles 调试微信小程序
联调阶段强烈推荐用 Charles 抓包。微信开发者工具虽然带了 Network 面板,但有时真机上的请求在开发者工具里看不到,特别是微信小程序的一些内部机制。用 Charles 抓包可以看到小程序真实的请求数据。
热搜里提到了“charles使用教程——使用charles抓包微信小程序”,我在这里补充几个关键点。真机调试时,必须把手机代理设置指向电脑的局域网 IP 和 Charles 的默认端口 8888,同时手机上要安装 Charles 的 SSL 证书。证书不装的话,HTTPS 请求显示为乱码,没法看内容。另外,微信小程序的 HTTPS 请求是校验合法证书的,Charles 的根证书必须设置完全信任,否则请求会直接被微信网络层掐断。
做了这一步,就能看到小程序到后端的全部请求,包括请求头、请求体、响应数据,排查接口问题会非常直观。定位接口返回慢,看耗时一目了然。
5.2 uniapp 打包微信小程序的必要配置
uniapp 的打包配置主要在manifest.json里。核心配置有:微信小程序 AppID、项目名称、版本号、是否启用组件按需注入、权限声明。权限声明很关键,比如用到定位功能,必须声明requiredPrivateInfos: ["getLocation"],不声明的话真机上调用uni.getLocation会直接返回错误。
打包的流程是:HBuilderX 菜单栏点“发行 → 小程序-微信”,编译完成后会在dist/build/mp-weixin目录下生成小程序产物。然后打开微信开发者工具,导入这个目录,就能进行预览和上传。
打包时会有一些样式差异。比如 uniapp 中的某些 CSS 属性和小程序不完全兼容。我遇到的典型问题是:position: fixed在小程序里在部分场景下表现不同,特别是键盘弹出时。针对这个,我用page-meta+ 自定义样式做了兼容处理。这类问题遇到一个解决一个就行,不必过度忧虑。
5.3 开发者工具白屏和登录态问题排查
开发阶段最容易遇到的疑难杂症是:代码在 HBuilderX 里编译正常,但打开小程序是白屏。白屏大概率是 JS 报错。打开微信开发者工具的 Console,看红色报错,最常见的是 uview-plus 插件加载失败、组件路径错误、或 app.vue 中引用了不存在的模块。
还有一个高频问题是“小程序 10002”报错,这个是微信登录流程中的错误码,一般出现在wx.login或code2Session阶段。可能原因:AppID 和 Secret 不匹配、IP 白名单没配、服务器时间不准。排查顺序也是这个顺序。我遇到过最坑的是服务器时间差了几十秒,导致 JWT 签名验证失败,token 签发失败,系统整个无法登录。后来在服务器配了 NTP 自动校时,问题不再出现。
登录态常遇到的问题是:在开发者工具里一切正常,但真机上用户重新打开小程序要求重新登录。原因是开发者工具默认不销毁小程序,但真机上小程序可能被系统回收,本地 token 丢失。我的解决策略是:token 存到uni.setStorageSync,有效期设 30 天,并支持后端刷新。只要用户 30 天内打开过,就保持登录。
5.4 上架微信小程序与安卓 App 的差异
热搜词里提到了“uniapp上架安卓应用市场”和“uniapp 微信小程序打包”,这里给做多端的同学说明一下。上架微信小程序只需要在微信公众平台提交审核,审核通过后发布即可。但如果是打包成安卓 App,就要走应用市场(华为、小米、OPPO、vivo 等)的审核流程。
App 端需要用云打包,在 HBuilderX 中配置打包证书,DCloud 提供测试证书可以快速体验,但上架必须有正式证书。App 上架还需要软著、隐私政策、ICP 备案等资质文件,这些周期比较长,想要上 App 的尽早准备。别把上架流程想太简单,应用市场的审核越来越严,不提前准备会很被动。
5.5 热更新与后台定位的问题背景
热搜词里的“uniapp App 热更新”和“后台运行监测定位”跟单独的小程序版本关系不大,但如果你确实要发布 App 版本,WGT 热更新是可行的。小程序本身没有热更新机制,只能走微信审核发布。后台定位能力在小程序端也有限制,小程序切到后台后,系统会逐渐挂起小程序,无法持续定位。在校园场景里,不需要后台定位实时上报,签到完成就结束了,没必要为了这个需求去碰平台的限制线。
6. 部署上线与运维建议
6.1 服务端部署
Python 后端部署我用的是腾讯云轻量服务器,2核4G的配置,跑这样一个系统绰绰有余。部署方式选择了 Docker Compose 一把梭,MySQL、Redis、FastAPI 三个容器一起编排起来。写 Dockerfile 的时候注意把依赖先安装好再拷贝代码,这样后续代码更新后重新构建,速度会快很多,因为依赖层有缓存。
上线前一定要做 HTTPS,微信小程序要求所有请求域名必须是 HTTPS,而且要在小程序后台配置 request 合法域名。服务器配 Nginx 反向代理到 FastAPI 的 8000 端口,SSL 证书用免费的就行,每年一换,脚本里写个自动续期。
6.2 数据备份与监控
上了生产环境之后,有两件事必须做:备份和监控。
MySQL 数据备份,我每天凌晨 3 点用mysqldump全量备份一次,保留 7 天,再同步一份到对象存储,防止服务器故障导致全丢。Redis 是缓存数据,丢失了可以从 MySQL 恢复,所以不单独做备份。
监控方面,FastAPI 集成了 Prometheus 客户端,上报接口请求量、耗时、错误率这些指标,Grafana 里配了几个图表看板。另外我写了一个简单的健康检查接口,定时脚本每隔 5 分钟请求一次,连续失败就推送告警到企微群。作为学校自研系统,运维能力有限,只有报警及时才能放假安心。
6.3 学期末高峰压力的应急预案
自习室预约系统有非常明显的波峰波谷:平时日活不过几百,期末考试周能飙到几千,早晨 8 点开馆那一瞬间并发会特别高。我针对这个特点做了预案。
数据库虽然用了连接池,但高峰期还是会有瓶颈。我的方案是:最热的查询(座位列表、空闲状态)走 Redis 缓存,接口层面加了一层本地内存缓存 + Caffeine 风格的自实现。Nginx 层做了限流,超过阈值的请求直接返回“系统繁忙”,避免把后端冲垮。高峰期过后再恢复默认限流策略。
这套预案在期末实测中表现得不错,最忙的时候系统响应依然控制在 1 秒以内,没有出现打不开的情况。
7. 常见问题速查与踩坑记录
这一节把开发过程中遇到的典型问题整理成一张速查表,可以说这些坑我基本都踩了一遍,写出来帮大家少走弯路。
| 问题现象 | 可能原因 | 解决思路 |
|---|---|---|
| 微信开发者工具白屏 | uview-plus 版本不匹配 Vue 版本 | 确认 Vue3 用 uview-plus、Vue2 用 uview |
| 控制台无日志输出 | 日志级别过滤或压缩代码移除日志 | 开发者工具日志级别设为 All,关闭压缩混淆 |
| 顶部导航栏错位 | 直接写死高度 | 用胶囊按钮动态计算高度公式 |
| 真机上无法定位 | 未声明 requiredPrivateInfos | manifest.json 中补充 getLocation 权限声明 |
| 座位被双人预约 | 缺乏并发控制 | 用 Redis SETNX 实现座位锁 |
| 预约高峰期接口慢 | 数据库直连查询太多 | 座位状态迁移到 Redis |
| 登录失败且报 10002 | AppID/Secret 不匹配 | 核对小程序后台配置并检查 IP 白名单 |
| App 上架被拒 | 资质材料不全 | 提前准备软著、隐私政策、ICP 备案 |
| 打包后自定义组件失效 | 组件路径或 easycom 配置错误 | 检查 pages.json 中 easycom 规则,确保组件安装完整 |
| 小程序分享出去无法打开 | 未配置分享路径或参数 | 自定义分享时补全 path 和 query 参数 |
实操经验里的几个核心心得再强调一遍:
- 需求文档一定要先写,别直接写代码。
- 微信侧的 AppID、Secret、模板消息这些必须先申请,审核周期按天算,拖到最后会卡住整体进度。
- 座位状态这种高频数据一定放 Redis,别死磕数据库。
- 定位签到的阈值要放宽,同时准备人工处理入口。
- 小程序编译器里的日志和构建日志是两回事,分清楚才能高效排错。
最后的个人体会:做完这个系统,我最深的感触是,技术难点其实不是最难的部分,最难的是把需求和边界定义清楚。自习室预约看着简单,但里面的座位状态一致性、预约冲突处理、高峰期性能,都是在细节里考验人的地方。好在这套方案从架构上就选了稳定的组合——uniapp 负责灵活跨端、Python FastAPI 负责快速开发和明确边界、Redis 补足状态读写的性能短板,整体跑下来算是一次比较成功的落地。如果你也在做类似的自习室、会议室、实验室预约系统,这套技术路线和踩坑记录可以直接参考,少走弯路。