ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

寄宿小学托管系统开发实战:微信小程序+FastAPI+Vue3全栈解析

寄宿小学托管系统开发实战:微信小程序+FastAPI+Vue3全栈解析 接这个“寄宿小学学生托管系统”需求的时候我以为就是套上一个常规打卡模板Python 写几个接口Vue3 搭个管理后台小程序端做个家长查询页一周搞定。真正接触了宿管老师、班主任和家长之后才发现寄宿托管有它自己的一套业务节奏——三餐登记、午休查寝、晚自习点名、周末留校统计、临时请假审批每个环节都有人要对孩子负责家长那边又隔着十几公里干着急。这篇文章不写广告式的项目介绍就把我们团队从零到一实现这套“微信小程序 Python Vue3”托管系统的完整思路讲透包括业务模型怎么设计、后端接口怎么拆、小程序端怎么做得顺手、管理后台怎么让老师们愿意用以及上架审核和支付功能踩过的那些真实大坑。如果你是接校园类外包的开发者或者学校内部想自建系统这份内容应该能帮你省掉不少调研时间。1. 先把业务吃透寄宿小学的托管需求不等同于“打卡机”很多开发者接到这种系统第一反应就是做考勤——到校打卡、离校打卡完事。但寄宿小学的“托管”是一整天都在学校围墙内进行管理颗粒度细得多。上午几点起床、几点吃饭、几点上课、午休谁在宿舍、晚自习谁没到、晚上熄灯后谁还没回寝这些节点如果全凭老师手工点名再抄到纸上最后录进电脑一个年级几十个孩子每天光是补录就能耗掉老师一个小时。系统的核心价值是把“孩子今天在不在、在哪个位置、状态正不正常”变成一条随时可查的数据流。1.1 寄宿托管特有的业务节点拆解我把整个业务流程画成了时间轴起床洗漱、早餐、上午课、午餐、午休、下午课、晚餐、晚自习、查寝熄灯。每个节点对应一条考勤类型后端用 type 字段区分比如morning、meal_breakfast、nap、self_study、sleep。不同节点的状态语义还不一样早起点名用“已到/迟到/请假”午休查寝用“在寝/不在寝/回家”晚自习用“出勤/缺勤/在宿舍/请长假”。状态枚举不能拍脑袋统一成一套否则宿管老师会骂娘。另一个被低估的场景是“周五离校/周日返校”。很多寄宿小学是周托制周五家长接走周日晚上送回来。接送高峰期保安亭门口挤满了人靠口头喊名字找孩子效率极低。我们做了一个“接送登记”功能家长在小程序端发起接领申请班主任在后台确认孩子已交到家长手上生成一条交接记录。真出了问题比如孩子被亲戚接走但家长不知情系统里有完整的时间戳和经办人责任划分一目了然。1.2 三端角色的权限边界和信息流这个系统的用户比普通小程序复杂至少五种角色超级管理员、班主任、宿管老师、财务、家长。我把权限边界画清楚之后后端的所有接口设计都是围绕角色来的。家长只能看自己绑定的孩子发起请假、查看缴费、接收通知。班主任管自己班级的考勤、审批请假、维护学生基础信息。宿管老师只管宿舍相关的考勤节点比如午休查寝、晚点名。财务只看缴费数据导出报表。超级管理员管全部用户、班级、宿舍、系统配置。前端两个入口对应两套权限体系小程序端只服务家长后台管理系统服务老师和财务。后台再按角色动态加载路由不要把按钮藏起来就算权限控制——直接在后端用 JWT 里的角色字段做接口级校验这是底线。1.3 技术栈选型为什么是“小程序 Python Vue3”而不是别的整个技术栈没什么花活但每个选择都是被业务逼出来的。小程序端用原生框架而不是 uni-app原因很简单这个项目不涉及多端发布微信生态的订阅消息、支付、地理位置这些能力原生支持最稳没必要引入跨端框架增加编译心智负担。Python 端没有选 Django用的是 FastAPI。Django 范式强、自带 Admin但这种纯 API 项目用 FastAPI 更轻——原生 async 支持高并发场景比如全校同时点名时的写入请求Pydantic 做参数校验省掉一堆手工判断自动生成的 Swagger 文档让前端联调直接对着网页看参数不用我一个一个复制接口文档。Python 生态里做数据清洗、报表导出的库也顺手。Vue3 后台则用了 Vite Pinia Element Plus 的组合。Vue3 的组合式 API 配合setup语法代码组织比 Options API 清晰太多尤其是点名台这种大量交互组件的页面逻辑复用全靠组合式函数。Pinia 比 Vuex 轻写起来更像普通模块对团队里的新人友好。Element Plus 的表单和表格组件成熟后台管理系统最耗时间的增删改查页面能省不少功夫。2. 后端核心设计FastAPI 如何把业务落地成接口后端是整个系统的承重墙。所有考勤记录、缴费单、请假审批都要经过它同时还要支撑小程序端和管理后台两个前端的并发调用。下面讲几个关键模块的设计思路以及代码层面最值得注意的细节。2.1 FastAPI 项目结构和环境配置项目根目录按模块划分而不是按文件类型堆app/ main.py config.py api/ v1/ __init__.py auth.py students.py attendance.py leave.py payments.py dashboard.py users.py notifications.py models/ __init__.py student.py attendance.py leave.py payment.py user.py schemas/ __init__.py student.py attendance.py leave.py payment.py core/ security.py deps.py constants.py services/ wechat.py payment_service.py sms_service.py开发环境我强烈建议用uv或poetry管理依赖不要裸用requirements.txt。这个项目涉及 FastAPI、Uvicorn、SQLAlchemy、Alembic、PyJWT、httpx、pydantic-settings、qrcode 等十几个依赖锁版本能避免半年后某人升级依赖导致全站报错的惨剧。VSCode 的 Python 环境配置也是个隐形坑。最好在项目根目录建.vscode/settings.json{ python.defaultInterpreterPath: ${workspaceFolder}/.venv/bin/python, python.terminal.activateEnvironment: true, python.linting.enabled: true, python.linting.pylintEnabled: false, python.linting.flake8Enabled: true }团队新人克隆代码后直接打开就能跑不需要手动切换解释器。2.2 核心数据模型一张图看懂表的关联关系数据库用 MySQL 8.0Redis 做缓存和计数。核心表结构大体如下表名关键字段说明usersid, username, password_hash, role, real_name, phone所有后台用户角色区分权限studentsid, name, student_no, gender, grade, class_id, dorm_building, dorm_room, bed_no, guardian_name, guardian_phone, guardian_openid学生档案一个学生绑定一个家长微信号class_groupsid, name, grade, head_teacher_id班级表班主任外键关联attendance_recordsid, student_id, node_type, record_date, status, operator_id, remark, created_at每日考勤流水数据量大需要索引leave_requestsid, student_id, start_time, end_time, reason, type, status, approver_id请假单审批流payment_ordersid, student_id, fee_type, amount, status, out_trade_no, transaction_id, paid_at缴费单对接微信支付notification_logsid, student_id, template_id, content, status, sent_at订阅消息推送记录考勤表是写入最频繁的。我给(student_id, record_date, node_type)加了联合唯一索引防止同一个人在同一天同一节点被重复点名同时按record_date做了分区半年前的流水归档到历史分区查询不拖慢。2.3 小程序登录态与 JWT 鉴权小程序端不是用账号密码登录而是走微信的code2Session流程小程序调用wx.login()拿到临时 code。前端把 code 发给后端/api/v1/auth/wx_login。后端拿 code 请求微信接口换取 openid 和 session_key。后端根据 openid 查用户没找到就自动创建一个家长账号并绑定关系用手机号人工匹配。签发 JWT返回给小程序。JWT 里包含 user_id 和 role有效期 7 天。JWT 的签名密钥不要放代码里用环境变量管理。后端所有受保护接口都依赖一个get_current_user依赖from fastapi import Depends, HTTPException, status from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from jwt import PyJWTError import jwt security HTTPBearer() def get_current_user( credentials: HTTPAuthorizationCredentials Depends(security) ): token credentials.credentials try: payload jwt.decode( token, settings.SECRET_KEY, algorithms[settings.JWT_ALGORITHM] ) user_id payload.get(sub) role payload.get(role) if not user_id: raise HTTPException(status_code401, detail无效凭证) return {user_id: user_id, role: role} except PyJWTError: raise HTTPException(status_code401, detail凭证已过期请重新登录)这段代码看着简单但实际开发有个容易忽视的点小程序端每次冷启动时都要静默调用wx.login刷新 token否则用户一周后打开小程序请求会 401。我的做法是在小程序请求封装里做统一处理一旦收到 401自动调wx.login重放一次请求用户完全无感。2.4 考勤点名接口幂等性和批量写入老师点名的场景是一次性勾选一个班二三十个孩子前端不可能每人点一次提交一次那样接口请求太多等待时间长。所以接口设计成批量提交POST /api/v1/attendance/batch Body: { node_type: self_study, record_date: 2025-06-18, records: [ {student_id: 101, status: present}, {student_id: 102, status: absent}, {student_id: 103, status: late} ] }后端用事务处理先检查当日该节点是否已经点名防止重复提交再批量插入。前端在弱网环境下可能重试请求所以必须做幂等基于(node_type, record_date, class_id)生成一个batch_id后端记录已处理的 batch_id重复请求直接返回第一次的结果而不是再插一遍。晚自习点名之后系统要自动干几件事生成异常记录应到未到的学生、给班主任推送一条订阅消息、在后台大屏上把该班出勤率刷一下。这些如果都放在请求里同步执行接口延迟会到两三秒。我用 FastAPI 的BackgroundTasks把消息推送和统计更新挪到异步任务里接口只负责写库200 毫秒内返回。2.5 请假审批链路一个两天不睡觉也要调通的状态机请假是托管系统里业务状态最复杂的模块。家长提交请假申请后状态是pending班主任审批后变approved或rejected但如果请假区间跨越了周五离校宿管那边也需要看到这条记录如果是病假还需要附加医院证明图片。这里有个细节请假的“单位”不是整天而是按节点来算。上午第四节课有点不舒服要早退这只影响午餐和午休两个节点请一整天才影响所有节点。所以后端把 leave_requests 存成时间段审批通过后自动在受影响日期范围内把考勤记录的状态置为leave。这一步一开始用 SQL 批量更新但牵扯到跨天问题时容易漏掉后来直接在审批通过事件里触发一个补偿任务逐日逐节点补齐简单粗暴但可靠。3. 小程序端开发家长手里那个“窗口”怎么做得顺手家长端小程序是这个系统的门面。老师们后台做得再复杂家长看不见家长每天打开小程序第一眼看到的东西决定了他对这个学校的信任度。所以小程序端的设计原则是信息要少而准操作要直接在首屏。3.1 页面规划与 TabBar 结构小程序端只有三个 Tab首页、消息、我的。首页展示当前绑定孩子的“今日时间线”早起点名状态、三餐完成情况、午休在寝状态、晚自习出勤。用卡片式纵向排列每个节点有绿/黄/红状态色家长不用点进去就能看到孩子今天所有关键节点是否正常。消息页是订阅消息的兜底入口。微信订阅消息是一次性订阅家长不主动订阅就收不到通知消息页里放系统公告和站内信。我的页面里包含孩子管理一个家长绑定多个孩子支持切换、请假申请、缴费记录、意见反馈。首页那个时间线数据来自一个聚合接口GET /api/v1/parent/dashboard?student_id101date2025-06-18后端一次性把当天所有节点查出来拼成一个数组返回前端只负责渲染不要在小程序端循环调多次查询接口。微信小程序对并发请求数有限制数据聚合尽量在后端做。3.2 请求封装统一的 loading、错误处理和登录态刷新小程序端我用一个request.js做统一封装所有接口都走它。核心逻辑包括自动附加 token、统一处理错误码、401 时自动刷新登录态并重放请求、网络错误时给出友好提示。const request (url, method GET, data {}, options {}) { return new Promise((resolve, reject) { const token wx.getStorageSync(token) wx.request({ url: ${BASE_URL}${url}, method, data, header: { Content-Type: application/json, Authorization: Bearer ${token}, ...options.header }, success: async (res) { if (res.statusCode 200) { resolve(res.data) } else if (res.statusCode 401) { const newToken await silentLogin() wx.setStorageSync(token, newToken) request(url, method, data, options).then(resolve).catch(reject) } else { wx.showToast({ title: res.data.detail || 请求失败, icon: none }) reject(res) } }, fail: (err) { wx.showToast({ title: 网络异常请检查网络, icon: none }) reject(err) } }) }) }这里踩过一个坑401 自动重放如果处理不好每次 token 过期后会有一次白屏请求用户看到页面一闪而过。我的解决方法是加一个isRefreshing标志token 刷新期间其他请求排队等待刷新完成后再统一重放而不是每个请求都各自调用一次wx.login。3.3 页面标题、订阅消息和节点状态的联动有些页面需要动态设置标题比如家长切换孩子后首页标题要变成“小明的一周”。小程序原生支持wx.setNavigationBarTitle在页面onLoad里根据参数设置wx.setNavigationBarTitle({ title: ${childName}的在校动态 })订阅消息是小程序端最有价值的触达手段也是最容易用错的功能。微信规定订阅消息必须由用户主动触发而且一次订阅只能推一条。我在设计时把订阅场景分成两类关键节点异常孩子晚自习缺勤、午休不在寝这些时家长最想立刻知道的在家长点击“开启通知”按钮时申请订阅。一般性通知每周托管费用账单、放假安排这些不紧急放在家长新绑定孩子时顺手订阅一次。实测下来订阅消息的打开率远高于小程序内部红点但前提是不要滥用。一天给家长推七八条“孩子已正常就餐”这种消息家长很可能会投诉到微信直接导致小程序被限制消息推送。3.4 微信支付小程序端只有三步服务端才是重头戏家长缴费是小程序端为数不多的闭环交易场景。支付流程很简单家长点击“去缴费”后端生成一个payment_order返回预支付参数。小程序调用wx.requestPayment拉起微信支付面板。用户输入密码支付成功后微信服务器回调后端接口更新订单状态。支付功能最容易出问题的是服务端不是小程序端。微信支付 v3 接口要求所有请求都要用商户私钥签名回调通知还要用平台证书验签。我们第一次对接时回调接口一直报“签名错误”排查了半天才发现是回调请求体被框架自动解析后签名验签时用的原始 body 已经被消耗掉了。正确做法是拿到原始字节流先验签验签通过后再解析 JSON。算法微信支付 v3 的签名拼接串 POST\n /回调路径\n timestamp\n nonce\n body\n回调处理还有个工程重点幂等。微信可能在超时后重复推送回调如果不做订单状态检查同一个订单会更新两次“支付成功”导致余额记录翻倍。处理方式是在回调里先查out_trade_no对应的订单状态如果已经是paid直接返回成功不再执行后续逻辑。3.5 富文本与隐私合规小程序审核的隐形门槛小程序端有一个“学校公告”模块后端返回 HTML 格式的富文本。小程序原生rich-text组件渲染 HTML 有很多标签限制样式也容易被忽略字体大小、颜色显示得乱七八糟。后来我统一在后端把 HTML 转成 JSON 结构带类型、内容、样式字段前端自己写渲染组件看起来丑但稳定。更关键的坑是隐私合规。微信官方要求小程序必须配置《用户隐私保护指引》如果采集了手机号、位置、相册等信息必须在小程序管理后台中声明。我们有家长上传孩子病历的场景一开始没声明“相册权限”审核直接被拒。还有一次因为没有在代码中调用wx.chooseMedia前先弹自己的隐私弹窗被平台判定“未经用户同意收集信息”。处理办法是引入官方wx.getPrivacySetting接口在进入涉及隐私的功能前先检查用户授权。4. Vue3 管理后台老师和管理员的工作台怎么设计才实用管理后台的使用者是学校老师他们不是程序员不会忍受复杂的交互。系统被判死刑的方式往往是老师用了一次觉得麻烦就回到“纸质点名 微信群通知”的老路。所以后台设计的第一原则是高频操作必须在三步以内完成。4.1 技术栈细节Vite Pinia Element Plus 的组合pnpm create vite初始化项目Vue3 TypeScript Element Plus 一把梭。状态管理用 Pinia把用户信息、当前班级、当前选中日期放在 store 里切换班级和日期时不需要在组件间层层传参。Vite 的开发体验比 Webpack 舒服太多冷启动基本在 1 秒内。不过有几个配置细节要注意// vite.config.ts import { defineConfig, loadEnv } from vite import vue from vitejs/plugin-vue import AutoImport from unplugin-auto-import/vite import Components from unplugin-vue-components/vite import { ElementPlusResolver } from unplugin-vue-components/resolvers export default defineConfig(({ mode }) { const env loadEnv(mode, process.cwd()) return { plugins: [ vue(), AutoImport({ resolvers: [ElementPlusResolver()] }), Components({ resolvers: [ElementPlusResolver()] }) ], server: { port: 5173, proxy: { /api: { target: env.VITE_PROXY_TARGET || http://127.0.0.1:8000, changeOrigin: true } } } } })unplugin-auto-import和unplugin-vue-components两个插件可以按需自动导入 Element Plus 组件不用全量引入打包体积能小不少。开发环境配置代理前后端分离联调时前端只认/api路径后端换个端口也不用改前端代码。4.2 登录、路由守卫和角色权限后台不能只用前端路由守卫控制页面访问真正的权限校验在后端接口。前端路由守卫解决的是“用户没登录不要显示页面”这种体验问题后端接口校验才是安全底线。登录页对接/api/v1/admin/login用手机号 密码换取 JWT存到 Pinia 和 localStorage。路由守卫在每次跳转前检查 token 是否存在不存在就跳转登录页。动态路由这部分我一开始想搞得很复杂根据角色动态生成路由表。后来发现这个项目角色就四种远没到需要复杂权限模型的程度。干脆把全部路由定义好路由的meta.roles字段标明哪些角色可以访问在守卫里过滤一遍router.beforeEach((to, from, next) { const userStore useUserStore() if (!userStore.token to.path ! /login) { next(/login) return } if (to.meta.roles !to.meta.roles.includes(userStore.role)) { next(/403) return } next() })好处是路由表一目了然不会有“某个角色看不到某个页面但通过 URL 直接访问就能进去”的安全漏洞——URL 直接访问在守卫里也会被拦截。4.3 点名台高频操作的核心交互点名台是整个后台使用频率最高的页面也是老师愿不愿意用系统的关键。设计上参考了在线表格左侧是班级学生列表按宿舍分组每个学生带头像右侧是批量操作栏。老师选中一个节点类型比如“晚自习”然后逐个点击学生头像切换状态绿色为已到、黄色为迟到、红色为缺勤。点击动作直接调用批量保存接口不单独设置“保存”按钮。老师可能在半分钟内完成整个班级的点名如果每点一个学生就发一次请求中间任何一次网络抖动都会让老师崩溃。所以我把交互改成“本地标记 定时批量提交”点击后数据留在本地 Vue 状态里页面一直显示未保存状态每 20 秒或离页时自动提交一次。这个设计初期被测试挑战过要是 20 秒内老师点了 10 个学生页面崩了怎么办我的回答是这是后台系统不是收银机极端情况老师重新进页面再点一遍而已。但为了稳妥起见我把未提交的数据存在 Pinia 里离开页面时触发beforeunload事件做一次强制保存同时后端幂等性保证重复提交不会出错。4.4 数据大屏和报表让管理者看见价值系统上线两周后校长会问你数据有什么用所以“数据大屏”其实是给项目续命的功能。我做了三个核心图表今日到校统计环形图显示全校/各年级出勤率按早晨、午餐、晚自习三个节点分别展示。晚自习异常趋势过去 7 天每天缺勤人数折线图方便发现“周三晚上缺勤多”这种规律。宿舍查寝状态楼层看板每一层显示各寝室人数、已在寝人数、未归人数宿管老师一眼看到哪个寝室还没查完。ECharts 在这个场景比纯组件库自带的图表好使配置灵活更新数据直接改setOption即可。Vue3 中我用一个useEchart组合式函数封装了图表初始化、自适应 resize、销毁逻辑避免每个图表组件重复写样板代码。export function useEchart(elRef: RefHTMLElement) { let chart: echarts.ECharts | null null onMounted(() { chart echarts.init(elRef.value) window.addEventListener(resize, resizeHandler) }) onBeforeUnmount(() { window.removeEventListener(resize, resizeHandler) chart?.dispose() }) const setOption (option: echarts.EChartsOption) chart?.setOption(option) return { setOption } }5. 三端联调与上架审核从代码到小程序商店的最后一公里项目开发最顺的阶段是各端自己写自己的最痛苦的是联调和上架审核。这里面的坑每一个都能让项目延期两三天。5.1 本地联调小程序如何访问本地后端小程序开发者工具有个“不校验合法域名”的选项开发模式下可以直接请求http://127.0.0.1:8000。但真机调试时手机不能访问电脑的 localhost需要把后端服务跑在电脑局域网 IP 上小程序请求地址改成http://192.168.x.x:8000。这里有个常见的尴尬手机和电脑连的都是公司 Wi-Fi但有些路由器开了 AP 隔离手机访问不了电脑 IP。我的迂回方案是在电脑上跑一个内网穿透工具生成一个临时域名小程序请求域名走临时域名网络上没有大坑请求也不会因为路径太深被截断。联调完关掉就好千万不要图省事把内网穿透地址留在正式代码里上架一旦暴露接口别人可以绕过登录直接调你的后端。真机调试时我还习惯用代理工具抓包看请求详情。小程序端的 HTTPS 请求在开发者工具里能看到 Network 面板但真机上出了问题比如某些 android 机型的证书校验失败靠日志很难定位。用 Charles 或 whistle 配置代理后手机流量转到电脑上能看到完整的请求头和响应体排查签名错误、回调没收到这类问题特别管用。注意别在公网环境下开着代理乱逛抓包工具只用于自己的调试环境。5.2 微信支付 v3从签约到回调验签的完整链路微信支付开通本身不是技术活但过程中的小坑不少商户号必须和小程序账号关联否则wx.requestPayment会报“商户号与小程序不匹配”。需要下载商户 API 证书p12 格式还要在商户平台配置 API v3 密钥和回调 URL。回调 URL 必须是公网 HTTPS 地址并且在微信支付后台配置白名单。服务端对接微信支付 v3 的流程可以总结为四步第一步生成预支付单。后端收到缴费请求后用商户私钥对参数签名请求微信的/v3/pay/transactions/jsapi接口拿到prepay_id。第二步签名小程序端拉起支付所需参数。返回给小程序端的不是prepay_id而是timeStamp、nonceStr、package、signType、paySign五个参数。第三步处理支付回调。微信服务器 POST 一个 JSON 到回调地址里面包含订单号、支付结果。回调处理函数要先用平台证书验签再解密resource字段拿真实订单信息。第四步更新订单状态。验签通过后更新payment_orders表把订单置为已支付同时把孩子当月的托管状态更新为”已缴费“。一个很容易被忽略的点微信支付金额单位是“分”不是“元”。一个托管费 1200 元后端下单时要传amount: 120000。我第一次联调时忘了乘 100用户支付 1200 分12 元就成功了还好是测试环境没出事——这种问题出在线上就是事故。5.3 类目审核和“违规支付”处理上架过程中最折磨人的环节微信小程序审核最大的坑不是代码是类目选择。托管系统属于“教育 - 培训机构”还是“生活服务 - 家政/托育”直接影响需要提交什么资质文件。我们第一次提交选了“教育”审核直接拒绝要求提供“办学许可证”。但实际上很多托管机构是家政服务性质并没有办学资质。换成“生活服务 - 托育服务”类目只需要提供营业执照审核就过了。你可能会问支付功能和类目有什么关系关系很大。微信支付要求小程序必须选择正确类目才能使用支付能力类目错了即使代码里已经接通了支付接口用户一发起支付就会提示“当前小程序支付功能暂时无法使用”。这个提示语就是网上大家常搜到的那句“由于小程序违规支付功能暂时无法使用”的触发条件之一。如果真遇到支付能力被限制不要慌处理链路如下在微信公众平台后台查看具体违规原因通常是因为类目选择不当或缺少资质文件。按提示修改服务类目上传对应资质。确认代码里没有诱导分享、没有未声明隐私采集行为。提交申诉附上情况说明一般 3-5 个工作日内会有结果。另外提醒一句有些开发者为图省事在审核版本里隐藏了支付入口上线后再打开——这个是严重违规行为轻则功能被下线重则小程序直接被封。千万不要尝试。5.4 上线后的监控和告警别等家长投诉了才知道系统挂了系统上线只是开始托管系统是每天早上 6 点到晚上 10 点都有用户使用的业务老师点名、家长查状态任何一个环节断了都会直接影响学校运营。我在后端接了一个简单的健康检查接口GET /api/v1/health返回{status: ok, db: true, redis: true}。服务器上用 Supervisor 跑一个定时任务每隔 5 分钟请求一次失败就 push 告警到微信群。同时用 Sentry 收集 Python 后端的异常堆栈前端 Vue3 的异常也接进来遇到问题不用等用户反馈就能在后台看到报错。上线后最重要的一个运维动作是数据库备份。考勤数据是学校的重要资产每天凌晨自动备份保留 30 天。虽然 MySQL 本身有 binlog但多一份逻辑备份总是更安心。几点踩坑之后才明白的体会这个项目真正跑起来和开发阶段的设想差距最大的地方在于老师们并不关心系统的技术架构他们只关心一个问题——能不能少敲几下键盘。我们的方案里点名台默认选中昨天的日期省去老师每天选日期的操作晚自习点名默认全部已到老师只需要把缺勤的单独标出来。这些细节看起来无关紧要但对用户粘性的影响比任何炫酷的页面都大。还有一个小技巧值得分享小程序端每次启动时不要急着让用户看到一堆数据而是先做一个回调后端更新“最近在线状态”的动作。这样后台大屏上能看到“某某家长 3 分钟前查看过孩子状态”这比冷冰冰的日活数据有用得多——它让校长和老师感受到家长真的在关心这个系统而不是学校自己装样子。最后说一句这种校园类系统的需求会因学校而异有的学校要加校车轨迹有的要对接宿舍门禁但核心的“学生档案 - 考勤节点 - 消息触达 - 缴费闭环”这四件事是共通的。把地基打稳后续不管需求怎么变都只是往上加模块而已。
返回列表