ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

微信小程序+PHP构建实验室考勤系统:框架选型与实战

微信小程序+PHP构建实验室考勤系统:框架选型与实战 1. 项目背景与需求拆解1.1 实验室考勤的痛点到底在哪先说结论实验室考勤和公司上下班打卡完全是两码事。公司打卡考勤基本就是人到了、时间对了就算过关但实验室的考勤场景要复杂得多——你不仅要记录谁来了还要记录谁什么时候走的在哪个实验室做了哪个实验有没有通过安全准入甚至还要处理临时请假、设备借用、助教排班这些乱七八糟的联动事项。我接手这个项目的时候实验室管理员的原始工作方式是纸质签到表 Excel 登记 月末手工汇总。听起来很落后但真实情况就是这样。每逢月底管理员要翻几十页签到记录统计每个人的出勤天数、迟到次数、缺勤情况再算成平时分工作量大不说还容易漏统计、算错数。另一个让管理员头疼的问题是安全管理。很多实验设备是有操作风险的不是所有学生都能随便进。以前的流程是学生签了到就进管理员根本没法实时判断这个人有没有经过安全培训。出了安全事故溯源也困难——纸质签到表上的字迹潦草日期还可能填错。所以这个项目的核心需求说到底就是三件事把考勤记录从纸质搬到线上学生用微信小程序扫码或定位签到后台自动生成记录月末自动出统计报表。把准入规则和考勤绑定只有通过了安全考试的学生才能签到进入对应的实验室。给管理员一个清晰的后台能在电脑上查看实时到岗情况、审批请假、导出统计数据。1.2 为什么是微信小程序而不是App这个决策其实没纠结太久。实验室的学生群体几乎人人都有微信小程序扫码即用、用完即走的特性正好匹配高频但轻量的考勤场景。如果做成 App学生要先下载安装、注册账号光是这一步就会流失一多半使用者。而小程序只需要在微信里搜一下或者扫个码整个签到过程不到十秒。后台管理端选择 Web 页面用 PHP 框架来写主要考虑的是部署成本低、服务器要求不高、实验室自己的服务器就能带得动。后面我会详细讲 ThinkPHP 和 Laravel 在选型上的权衡这里先不展开。1.3 这个项目适合谁参考如果你是计算机相关专业的毕业生正在纠结毕业设计选题或者你在高校实验室、培训机构做管理工作想把手动考勤改成线上系统再或者你只是想看一套完整的微信小程序 PHP 后端实战案例——这篇文章都能给你点实际的东西。我会按真实的开发顺序来讲从需求整理、技术选型到数据库设计、接口开发再到小程序端对接和上线部署最后附带我自己踩过的坑。2. 技术选型ThinkPHP 和 Laravel 的权衡实录2.1 同一套系统为什么纠结两个框架标题里同时出现了 ThinkPHP 和 Laravel可能有人会问你到底用哪个实话说我前期用 Laravel 写了一版后台原型中期因为部署环境和团队熟悉度的原因又用 ThinkPHP 重写了核心模块。最后交付的版本是以 ThinkPHP 为主干、参考了 Laravel 的一些设计思路。这个经历本身挺有代表性值得展开说说。先说说两个框架在我实际使用中的直观感受。Laravel 的优势在于工匠精神——Composer 依赖管理规范Eloquent ORM 非常优雅写关联查询几乎不用拼 SQL中间件、事件监听、队列这些基础设施开箱即用。尤其适合从零搭建、结构清晰、后续可能要持续迭代的项目。但它的缺点也明显对服务器环境要求偏高至少 PHP 7.4 加上一堆扩展首次加载性能一般在不做优化的情况下并发稍高就会出现响应变慢。对学生项目来说还有一个隐形门槛Laravel 的学习曲线比 ThinkPHP 陡峭如果团队里有人只接触过原生 PHP 或者 ThinkPHP 3.x让他直接上手 Laravel前期沟通成本会很高。ThinkPHP 的优劣势正好反过来。它对 PHP 版本要求宽松部署在普通的 Apache/Nginx PHP 5.6 环境上都能跑上手快文档是中文的遇到问题搜索引擎能捞到大量现成答案单库查询性能在同量级下优于 Laravel 默认配置尤其适合中小型管理系统这种读多写少、表结构稳定的场景。缺点就是架构思想上相对传统比如 ORM 的关联处理、依赖注入、容器这些概念不像 Laravel 那么彻底写复杂业务时要自己多写一点代码。2.2 我的选型决策逻辑选型这件事不能单看框架本身要结合项目实际情况。我的决策逻辑有三个维度部署环境实验室的服务器是一台用了五年多的老机器操作系统是 CentOS 6PHP 版本 5.6。装 Laravel 理论上可以但需要升级 PHP、装扩展、改虚拟主机配置动到服务器的系统环境就有风险。而 ThinkPHP 5.x 对 PHP 5.6 的兼容性很好几乎是解压就能跑部署成本最低。团队成员参与开发的两位同学一位熟 ThinkPHP一位半路出家。如果选 Laravel至少要给他们一周的框架学习缓冲期。选 ThinkPHP第二天就能开始写业务代码。业务复杂度实验室考勤系统的核心表大概七八张关联关系不算深事务处理也不复杂ThinkPHP 的模型层够用。Laravel 的强大功能在这个量级下属于杀鸡用牛刀反而徒增维护成本。这里给一个实用建议如果你做的是毕设选框架之前先查清楚你们学校实验室或答辩老师普遍熟悉哪个框架。很多老师对 Laravel 的认可度比较高因为它更现代化但如果你能用 ThinkPHP 把系统做得扎实、逻辑清晰同样能拿高分。关键是你能讲清楚为什么选它而不是无脑跟风。2.3 两套框架混合开发的一个稳妥姿势如果你也面临团队有人熟 TP 有人熟 Laravel的尴尬我提供一个折中方案用 ThinkPHP 做主框架但把代码结构写得Laravel 化——控制器尽量薄业务逻辑抽到 Service 层数据操作走模型层配置放到独立文件。这样既享受了 TP 的部署便利又保留了 Laravel 式分层带来的可维护性。后面重构时如果非要切到 LaravelService 层和模型层的迁移成本会低很多。3. 系统整体设计与数据库建模3.1 角色权限模型怎么定考勤系统涉及三类角色学生、管理员实验室老师或助教、系统维护员可能就是你自己。我没有单独建角色表而是用type字段在用户表里区分简单直接。原因很简单角色不多、职能明确没必要引入 RBAC 那套复杂的权限管理。如果未来要扩展成校级平台、增加多角色多权限再升级不迟。用户表的角色字段我设计了四个值0学生默认角色通过小程序注册后就是这个1普通管理员可以审批请假、查看考勤记录、导出统计2超级管理员在普通管理员基础上还可以管理用户、管理实验室设备3系统维护员数据库和系统配置层面的操作权限实际开发调试用3.2 数据库表设计详解整套系统一共设计了 11 张表核心的几张我列一下用户表user字段名类型说明idint(11) PK用户IDopenidvarchar(64)微信小程序登录凭证唯一索引nicknamevarchar(50)微信昵称real_namevarchar(20)真实姓名必须实名登记student_novarchar(20)学号考勤统计用phonevarchar(20)手机号从小程序端获取avatarvarchar(255)头像URLtypetinyint角色类型is_safety_passedtinyint是否通过安全考试create_timedatetime注册时间实验室表lab字段名类型说明idint(11) PK实验室IDlab_namevarchar(50)实验室名称lab_codevarchar(20)实验室编号用于签到码locationvarchar(255)物理位置描述latitudedecimal(10,7)纬度longitudedecimal(10,7)经度radiusint(11)考勤允许误差半径单位米is_requires_safetytinyint进入是否需要安全准入statustinyint启用状态考勤记录表attendance字段名类型说明idint(11) PK自增主键user_idint(11)学生用户IDlab_idint(11)实验室IDtypetinyint1签到 2签退timedatetime打卡时间sourcevarchar(20)签到方式扫码/手动statustinyint1正常 2迟到 3早退 4异常请假表leave_request字段名类型说明idint(11) PK主键user_idint(11)请假人lab_idint(11)请假涉及的实验室start_timedatetime开始时间end_timedatetime结束时间reasonvarchar(255)请假原因leave_typetinyint1事假 2病假 3其他statustinyint0待审批 1同意 2拒绝approve_user_idint(11)审批人approve_timedatetime审批时间approve_notevarchar(255)审批意见设计这 11 张表时我总结了三个经验每个表必须有主键且为自增 int不要用 UUID 之类花里胡哨的东西——PHP 框架对自增主键的支持最友好查询效率也最高。时间字段统一用 datetime别用 int 存时间戳。虽然 int 省空间但查出来还得date()转格式而且写 SQL 调试时看一串数字完全不知道是哪天。外键不要真的加物理外键约束逻辑关联用索引维护就好。我之前加过物理外键结果插入数据时动不动报错调试排查还麻烦后来全删了。3.3 小程序端的功能模块划分小程序端页面不多核心是五个页面首页展示当前日期、本周出勤统计、待处理事项比如请假审批待办仅管理员显示、快捷签到入口。签到页核心功能页。进入后自动定位显示所在位置点击签到或签退按钮后台校验位置和时间返回结果。记录页查看个人历史考勤记录按月份筛选迟到/早退用颜色标注。请假页提交请假申请填写起止时间、原因、类型管理员端在这里多一个审批列表。我的页个人信息展示、安全考试状态、实验室列表管理员可维护。3.4 管理后台页面规划后台用 Bootstrap 做了一套响应式界面功能不复杂但页面不少仪表盘今日签到人数、当前实验室在线人数、请假待审数量用户管理学生列表、启用/禁用账号、重置安全状态实验室管理增删改查实验室设置签到半径考勤管理多维筛选考勤记录按日期/用户/实验室导出 Excel请假管理审批列表一键通过/拒绝填审批意见统计报表月度出勤统计表按班级/个人生成报表4. 核心功能模块实现与接口设计4.1 微信登录与手机号获取小程序端登录流程用的是微信官方推荐的wx.logincode2Session换 openid 的方式。这一步有个细节容易踩坑openid 必须作为用户的唯一业务标识不能把用户 id 直接暴露给小程序端。我见过有人把数据库自增 id 当用户标识传给前端虽然能让代码写得省事但安全隐患极大——别人可以通过枚举 id 刷别人的数据。手机号获取这里微信在 2023 年后把通过wx.getPhoneNumber获取手机号规则调整得严格了必须是企业主体的小程序并且完成认证个人主体的小程序无法使用这个接口。如果你也是个人开发者做毕设调试时用测试号 手动绑定手机号的方案更可行在小程序端登录后弹窗让用户手动填写手机号后端做个验证码校验用阿里云短信或腾讯云 SMS虽然多一步操作但能绕开企业认证的限制。我当时的交互流程是小程序端wx.login()拿到 code。后端通过code2Session换取 openid 和 session_key。先查用户表如果 openid 不存在则自动创建一条未完善信息的用户记录。前端引导用户填写真实姓名、学号、手机号提交后更新用户信息。信息完善后进入首页开始正常使用。这里要提醒一句session_key 是敏感信息绝不能下发给小程序端。它用来解密手机号等敏感数据如果泄露别人可以伪造你的身份后端务必只保存 openidsession_key 用后即弃。4.2 考勤签到的算法与防作弊签到功能的两个核心参数是位置和时间。位置校验用的是经纬度距离计算。小程序端通过wx.getLocation获取当前经纬度传给后端后端计算与实验室坐标的球面距离在设定半径内才能打卡。球面距离公式我用的是 Haversine 公式PHP 代码实现如下function haversineDistance($lat1, $lng1, $lat2, $lng2) { $earthRadius 6371000; // 地球半径单位米 $latFrom deg2rad($lat1); $latTo deg2rad($lat2); $deltaLat deg2rad($lat2 - $lat1); $deltaLng deg2rad($lng2 - $lng1); $a sin($deltaLat / 2) * sin($deltaLat / 2) cos($latFrom) * cos($latTo) * sin($deltaLng / 2) * sin($deltaLng / 2); $c 2 * atan2(sqrt($a), sqrt(1 - $a)); return $earthRadius * $c; }默认签到半径设为 200 米不能设太小因为 Wi-Fi 定位和基站定位的误差常常有二三十米也不能设太大否则学生在隔壁宿舍都能签上。时间校验的逻辑是每个实验室可设置上午、下午、晚上三个考勤时段迟到判定为晚于开始时间 10 分钟以上。我的实现方式是在实验室表里加一个time_slot_config字段存 JSON比如{ morning: {start: 08:00, end: 12:00}, afternoon: {start: 14:00, end: 18:00}, evening: {start: 19:00, end: 22:00} }签到时后端取当前时间判断落在哪个时段内对比开始时间判定是否迟到。防作弊这块我做了三个处理后端位置校验为主不能信任前端传过来的经纬度直接入库必须拿前端坐标去和实验室坐标算距离防止有人改包或抓包伪造坐标。签到频率限制同一用户同一实验室同一时段只能签到一次防止重复打卡。异常签到标记如果签到时定位距离过远比如大于 2000 米依然记录但标记为异常由管理员后续人工确认。4.3 请假审批的状态机设计请假流程不复杂但要处理的状态逻辑还不少。我设计的状态流转是待审批(0) → 同意(1) 拒绝(2) (不可逆)很简单的三态模型但因为要支持销假操作学生提前结束请假我在后面扩展了一个已销假(3)状态。实际效果是学生请假两天结果半天就处理完了可以销假回来签到避免被误判为缺勤。审批时后端逻辑要注意权限校验只有 type 为 1 或 2 的用户才能审批普通学生提交的审批请求必须返回 403。这个权限判断写在 Service 层而不是控制器层防止在多个接口里重复编写导致遗漏。4.4 统计报表的实现方案考勤统计这块我吃了不少亏总结出相对好用的方案延迟计算 缓存比实时计算可靠得多。刚开始我用了每次查询都动态汇总统计的方式数据库扛不住是一方面逻辑也容易出 bug——比方说月末汇总时如果有学生请假被修改状态统计数字就对不上。后来我改成每天凌晨跑定时任务生成当天的统计快照存进attendance_daily_summary表查询时直接读快照数据一致性和查询速度都有保障。定时任务用 ThinkPHP 的命令行任务php think crontab核心代码如下// 伪代码示意 public function dailySummary() { $yesterday date(Y-m-d, strtotime(-1 day)); $startTime $yesterday . 00:00:00; $endTime $yesterday . 23:59:59; // 按用户分组统计 $records Db::name(attendance) -where(time, between, [$startTime, $endTime]) -where(type, 1) // 只统计签到 -select(); // 聚合计算并写入 summary 表 // ... }导出 Excel 我用了 PHPExcel对就是已经不算新的那个库。在 ThinkPHP 中引入很简单用 Composer 装phpoffice/phpexcel然后写一个导出方法。注意导出大文件时设置内存上限否则 PHP 会直接崩掉报Allowed memory size exhausted这在处理几百人一个月的记录时真的会发生。5. 微信小程序端的关键技术细节5.1 顶部导航栏高度适配微信小程序的顶部导航栏有一个问题不同机型、不同系统iOS/Android的导航栏高度不一样。如果程序页面需要自定义头部直接写死padding-top就会导致在部分手机上内容被遮挡。通用做法是通过wx.getSystemInfoSync()获取状态栏高度然后动态设置const systemInfo wx.getSystemInfoSync(); const statusBarHeight systemInfo.statusBarHeight; // 状态栏高度 const navBarHeight 44; // 导航栏内容高度iPhone X 以后是 44其他机型 44 或 48 Page({ data: { statusBarHeight: statusBarHeight, navBarHeight: navBarHeight }, onLoad() { // 动态计算自定义导航栏总高度 const winWidth wx.getSystemInfoSync().windowWidth; // 胶囊按钮位置右上角胶囊 const menuButton wx.getMenuButtonBoundingClientRect(); const navHeight (menuButton.top - statusBarHeight) * 2 menuButton.height; this.setData({ statusBarHeight: statusBarHeight, navHeight: navHeight }); } });用wx.getMenuButtonBoundingClientRect()获取胶囊按钮的位置然后反推导航栏高度这个方法目前我在各机型上测试都比较稳妥。注意在自定义导航栏的页面里navigationStyle要设置为custom否则默认导航栏和自定义导航栏会叠加页面直接变两层。5.2 微信小程序签到定位的坑wx.getLocation接口有几点要特别注意要在app.json里声明permission配置否则首次调用会直接被系统拦截permission: { scope.userLocation: { desc: 您的位置信息将用于实验室签到考勤 } }定位前要先检查用户授权状态如果用户拒绝过授权需要引导到设置页打开授权。我这里写了一个工具函数function checkAndGetLocation() { 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: reject }); }, fail() { // 引导去设置页 wx.showModal({ title: 提示, content: 需要位置权限才能签到请在设置中开启, confirmText: 去设置, success(res) { if (res.confirm) { wx.openSetting(); } } }); reject(new Error(DENY)); } }); } }, fail: reject }); }); }coordType 的选择国内小程序要用gcj02国测局坐标不要用wgs84GPS 原生坐标。因为微信提供的地图和多数国内地图服务都是基于 gcj02 加密偏移的用 wgs84 会导致坐标偏移几百米。如果你存的是 wgs84定位在实验室正门口却提示距离过远大概率就是坐标偏移问题。5.3 微信小程序的单选框与表单考勤记录页的筛选功能里用到了单选框小程序原生radio-group的行为有点反直觉——它不支持通过value属性直接设置默认选中项必须用checked标记或者通过radio-group的bindchange事件动态设置。我写了一个简单方案radio-group classfilter-group bindchangeonFilterChange label wx:for{{filters}} wx:keyvalue radio value{{item.value}} checked{{item.checked}} color#1aad19 / text{{item.label}}/text /label /radio-groupdata: { filters: [ { label: 全部记录, value: all, checked: true }, { label: 正常, value: normal, checked: false }, { label: 迟到, value: late, checked: false }, { label: 早退, value: early, checked: false }, { label: 异常, value: abnormal, checked: false } ] }, onFilterChange(e) { const val e.detail.value; this.setData({ currentFilter: val, filters: this.data.filters.map(item ({ ...item, checked: item.value val })) }); // 重新请求记录列表 this.fetchRecords(val); }5.4 订阅消息与请假审批通知请假审批结果需要通过微信订阅消息推送给学生。设置订阅消息时发现一个坑一次性订阅模板用户每次都要授权而长期订阅模板仅对特定场景开放比如政务、医疗等普通小程序没有长期订阅权限。我的方案是在用户提交请假申请时前端弹窗请求订阅授权复用同一个模板后端在审批通过后发送一次性订阅消息。如果用户当时没授权就退而求其次——小程序端提供一个待办通知列表学生主动查看审批结果。实际用下来大部分学生都会在提交请假的瞬间顺手点一下授权所以效果还行。发送订阅消息的后端实现ThinkPHPuse think\facade\Cache; public function sendLeaveNotice($userId, $result, $startTime) { $user User::find($userId); $accessToken Cache::get(wx_access_token); if (!$accessToken) { $accessToken $this-getAccessToken(); Cache::set(wx_access_token, $accessToken, 7000); } $url https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token . $accessToken; $data [ touser $user[openid], template_id 你的模板ID, page pages/index/index, data [ thing1 [value 实验室请假], phrase2 [value $result], time3 [value $startTime] ] ]; // 发送 post 请求... }注意access_token一定要缓存起来微信接口的access_token有效期只有 7200 秒频繁获取会被微信限流报45009错误。6. 常见问题与排查技巧实录6.1 微信登录偶发失败code 只能用一次这是我在调试小程序登录时遇到的第一个问题现象是用户第一次登录正常退出再登录就报无效的 code。查了半天发现是wx.login返回的 code 只能用一次用完就作废。我之前误把 code 缓存了起来第二次请求用的是缓存中的旧 code所以报错。正确做法是每次登录都重新调wx.login()获取新的 code不要尝试复用。如果业务上需要静默登录可以封装一个ensureLogin方法每次校验本地是否有 openid没有或失效就重新调wx.login()。6.2 定位偏差导致签到失败有一个学生反馈我就在实验室里面却提示距离太远。日志发现该学生的上报坐标和实验室坐标差了有 700 米。排查后原因是他手机系统开启了模糊定位微信拿到的坐标是基站级别的粗精度而非 GPS 精确定位。这个问题没法在小程序端强制用户关闭只能在签到页加一个定位精度提示检测到精度超过 100 米就提示当前定位精度较低请到窗边或空旷处重新定位提高签到成功率。6.3 小程序段号超过 2MB 无法预览开发过程中往小程序里塞了不少图片结果编译时提示代码包超过 2MB。这里我踩过的坑值得分享别把图片放本地必须放服务器或 CDN首屏页面拆分包处理。具体做法是大图全部换成压缩后的webp或jpg格式控制在 50KB 以内。把非核心页面实验室详情、历史记录、帮助中心放进分包subPackages。公共组件用lazyCodeLoading: requiredComponents配置按需加载。还有一个隐藏技巧小程序开发工具里可以开启上传时压缩代码能再省一点空间。如果实在超了太多检查project.config.cn里的minified设置是否开启。6.4 并发打卡数据竞态问题考勤签到接口在上午 8:00 到 8:10 之间会收到密集请求如果两个人同时提交签到可能插入两条记录。我的解决方式是在数据库层加了用户时段类型的唯一索引ALTER TABLE attendance ADD UNIQUE INDEX idx_user_time_type (user_id, time, type);同时后端在插入前用select ... for update做行锁双保险。实测下来并发一百个请求也不会产生重复打卡。6.5 服务器上传接口的坑PHP 最大上传大小限制学生上传头像和请假证明材料时有时会报上传失败。排查后是 PHP 配置的upload_max_filesize默认只有 2M改成 10M 后正常。如果你也遇到类似问题修改php.ini后别忘重启 PHP-FPM否则不生效。6.6 小程序登录态失效问题wx.login的 session_key 有效期不固定如果用户长期不打开小程序登录态会过期。我在用户表加了一个last_login_time每次请求时检查session_key的存活时间超过 48 小时就强制重新登录。方法是在后端的用户鉴权中间件里做判断过期则返回特定的code: 401小程序端捕获到这个状态码后自动触发重新登录流程用户无感。7. 工具链与调试技巧7.1 抓包工具在小程序联调中的妙用开发小程序接口联调时查接口返回数据前后端经常对不上这里我强烈建议直接上抓包工具。PC 端微信小程序可以通过 Charles 或者 Reqable 抓包看到小程序发起的完整请求和响应体排查前端传的参数对没对后端返回的结构是不是预期格式非常直观。具体配置不展开简单说思路手机和电脑连同一个局域网手机设置 HTTP 代理到电脑的 IP 端口安装抓包工具提供的 CA 证书就可以解密 HTTPS 流量。注意微信小程序在调试模式下可以开启开发者工具的网络面板更方便但如果要真机调试抓 HTTPS 包几乎是唯一手段。7.2 ThinkPHP 调试模式的正确打开方式ThinkPHP 的调试模式很多人只是当开关用没善用它的日志。我在config/app.php里把app_trace true打开后浏览器底部会出现一个调试工具栏可以看到每次请求的 SQL 语句、执行时间和内存占用。开发阶段排查性能问题全靠它。线上环境务必把app_debug false并且关闭 trace否则暴露敏感信息是小性能损耗是大。7.3 定时任务和计划任务的调试ThinkPHP 的定时任务在 Windows 开发机上没法跑我用的方案是开发阶段手动触发一个debug参数比如php think crontab --actionsummary --date2025-06-01这样可以断点调试计算逻辑。上线后用系统 crontab 每分钟执行一次调度器核心命令如下* * * * * cd /www/wwwroot/your-project php think crontab /var/log/attendance_cron.log 21注意给 PHP 设置足够的内存统计大表数据时默认 128M 不够用我设的是 512M。8. 安全加固与上线部署8.1 小程序接口防刷与鉴权接口鉴权我用的是自定义 Token 方案用户在登录成功后后端生成一个token用 JWT 或者简单一点用md5(openid salt time)存缓存并返回给前端。前端每次请求在 header 里带Authorization: Bearer token后端中间件统一校验。处理逻辑如下校验 token 是否存在且未过期通过 token 找到对应用户 id 和角色将用户信息挂到请求上下文后续逻辑直接获取8.2 后台管理端的登录保护后台是独立于小程序的 Web 管理页面我用的是会话登录。这里有个很关键的细节管理后台的接口必须和小程序端接口分离鉴权不能复用同一套 token 体系。防止有人从小程序端逆向出接口地址后直接调用管理员接口操作数据。我的做法管理后台单独用admin_user表登录后生成一个独立的admin_token存到服务端 session 或 Redis所有后台接口统一校验这个 token同时检测访问 IP 和客户端 UA。8.3 服务器环境部署实录实际部署时我用的环境是 Nginx PHP-FPM MySQL 5.7。上传代码到服务器后执行composer install --no-dev --optimize-autoloader php think migrate:run chmod -R 755 runtime chown -R www:www runtime/记得把静态资源图片、上传文件的目录权限改对否则学生传不了头像。如果用了 Nginx配置伪静态让所有非静态文件请求走index.php入口location / { try_files $uri $uri/ /index.php?s$uri$args; }8.4 上线前检查清单我整理了一份上线前必查清单可以抄作业微信小程序后台配置合法域名request、uploadFile 必填关闭不校验合法域名的调试选项后台管理页面修改默认管理员密码删除安装目录或锁定安装文件数据库备份一次完整数据库导出所有表结构PHP 配置检查display_errors关闭log_errors开启upload_max_filesize加大定时任务用crontab -l确认调度器在跑手动执行一次统计任务确认数据落表日志清理runtime 日志目录写个清理脚本防止长时间运行磁盘满9. 从开发到交给管理员使用还有哪些事没做完到这里项目的核心开发基本完成了。但我必须说一个系统从能跑到真好用之间还有一段很长的路。这段路主要不是代码而是跟实际使用者之间的磨合。我给实验室管理员验收的时候管理员提了三个需求都是我最初没想到的第一个是批量导入学生名单。管理员有全校学生的 Excel 花名册他不想一个一个在小程序里注册。我后来加了一个导入名单按钮上传 Excel 后按学号匹配一键生成待激活账号学生首次登录时绑定 openid 即可。第二个是迟到分时段统计。管理员需要知道哪些学生经常在迟到边缘比如 8:09 打卡他想单独发消息提醒这些学生。我加了一个迟到预警报表按最近一个月迟到次数排序。第三个是导出格式的定制。管理员想要导出的 Excel 里能直接看到第几周到第几周的出勤汇总还要能打上学院和专业筛选。这个改动说大不大说小不小核心是给用户表加了college和major字段然后统计 SQL 里加了分组维度。这些需求让我明白一件事做系统不是写完代码就结束而是要在使用中不断迭代。尤其是这种面向管理员的内部系统最终评价标准是管理员觉得顺不顺手而不是功能列表有多长。最后说一个我个人的体会技术选型上的纠结ThinkPHP 还是 Laravel其实远没有想象中重要真正决定项目成败的是需求调研够不够细、数据模型清晰不清晰、联调和测试到不到位。我在这个项目里因为前期需求没聊透中途加了好几次功能返工了不少代码。如果你也在做类似系统建议把第一步花在跟管理员坐在一起看他怎么工作上这份时间投入一定物超所值。
返回列表