ARTICLE DETAIL

资讯详情

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

基于小程序的上门维修系统毕业设计源码实战

基于小程序的上门维修系统毕业设计源码实战 简介这份基于小程序的上门维修系统源码是面向小程序开发学习者与计算机相关专业毕业设计/课程设计的一站式项目。系统完整实现用户、维修员、管理员三端用户可管理维修信息、维修记录、评价与收藏维修员可处理维修进度与评价管理员则统一维护用户、维修员、维修信息、评价及广告等后台模块。资源包共1249个文件、26.06MB包含123个Java后端核心类、145个Vue前端组件、226个JavaScript脚本以及大量png/svg界面素材和wxml/wxss小程序页面文件同时附带SQL数据库文件前后端代码结构完整导入工具即可运行。目前已有121人学习下载适合作为毕业设计源码参考或小程序项目实战练习。压缩包内还包含Maven配置、部署脚本install/run/build与说明文档可帮助快速搭建环境并梳理三端业务流程直接支撑课题撰写与功能展示。1. 上手之前先搞清这套“上门维修系统”能帮你省什么力气如果你正在为毕业设计发愁或者想快速交付一个能演示的“小程序 管理后台”项目那么“基于小程序的上门维修系统源码小程序毕业设计完整源码LW.zip”很可能就是你搜索列表里那个看起来最完整的包它包含前端小程序、后端服务、数据库脚本和一个能直接导入微信开发者工具的工程目录通常还附带LW也就是毕业论文/设计文档。它的典型场景是用户在小程序里提交家电、水管、电路等维修订单维修师傅端能看到待接单列表管理员在后台完成派单和统计。本文会把它从“能跑”讲到“能改”再到“能答辩”中间穿插参数调整和最常见的翻车点帮你把这份源码变成真正属于你自己的毕业设计。2. 把源码拆开看技术栈、功能边界和“LW”到底指什么2.1 一套毕业设计项目应具备的完整技术栈上门维修系统的常见做法是“微信小程序原生前端 Java后端 MySQL数据库”三段式。小程序端一般是原生 WXML/WXSS/JavaScript不放复杂框架这样在微信开发者工具里导入即用后端以 Spring Boot 居多少数是 SSMSpring MVC MyBatis Servlet或者直接用 Node.js 写一写接口。判断你手上这套源码属于哪种最快的方法是看解压后是否出现 pom.xml有就是 Maven 管理的 Java 项目没有则优先怀疑是 PHP或 Node 写的“假后端”。选型原因也很直白毕设答辩时老师最关心“为什么用这个技术”原生小程序 Spring Boot 的组合意味着你可以在“小程序端页面渲染”“后端接口设计”“数据库表关系”三个方向分别展开每个方向都能讲出深度。如果是 uniapp 工程则需要先在小程序模式下重新编译再把 dist 目录导入微信开发者工具这里多出的“打包”步骤是答辩时的加分点但也是一些同学第一次卡住的地方——导入 dist/build 目录而不是源码根目录否则开发者工具里看到的永远是空白。功能边界上这类系统一般不会做支付整套闭环更多是“模拟支付”或“到付”。别指望包里自带微信支付商户号配置那是需要企业资质和密钥的个人小程序的毕设项目通常用不到。“上门维修”的核心闭环是用户报修 → 师傅接单 → 上门完成 → 用户评价外加管理后台的审核、派单、统计。理解了这个闭环你就知道源码里各个文件夹存在的意义了。2.2 从数据库表往前倒推维修订单的生命周期拿到源码后别急着跑先打开数据库脚本通常是 db 目录下的 .sql 文件里边的表结构直接决定了你能改出什么样的业务。典型的上门维修系统至少包含这些表表名核心字段在业务里的作用userid, openid, nickname, phone, address用户登录与个人信息tech_userid, name, phone, skill_type, status维修师傅资料与接单状态repair_orderid, user_id, tech_id, status, service_type, appointment_time, address, description, pay_status, price, create_time整个系统的主动脉order_commentid, order_id, user_id, rating, content, create_time用户评价与师傅评分来源admin_userid, username, password, role后台登录账号其中 repair_order 表是理解整个项目的钥匙。它的 status 字段通常会按数字或字符串定义多个状态0 待派单、1 已接单、2 维修中、3 已完成、4 已取消。前端列表页、“加载更多”、师傅接单按钮、后台派单页面全部围绕这个字段转。如果你在 SQL 脚本里找不到 repair_order、只看到类似 order_info 的表名不要慌字段逻辑是相通的。真正要检查的是订单表是否包含 address 和 phone 字段。有些“半成品源码”把用户地址存在了 user 表里订单只存“用户ID 描述”这种设计在上门维修场景里是致命的——师傅不知道去哪上门。如果你的包存在这个问题在答辩前一定要把 address 字段补回订单表这是一个能在答辩桌上让老师眼前一亮的小改动。2.3 “LW”和“完整源码”的关系别把论文当附赠品压缩包名称里的“LW”在毕设圈里几乎约定俗成就是指“论文”大多数人理解为 Literature Writing 或 论文文档的缩写。它通常是一个 Word 文档包含需求分析、系统设计、数据库设计、核心代码展示和测试用例这些章节。这里要特别提醒把源码改好只是第一步毕业设计评分里论文/文档的占比往往不低于 40%。源码包里附带的 LW 文档一般是原作者针对他自己的系统写的里面的截图、表结构、代码片段和你实际跑起来的版本未必完全一致。所以正确做法是先跑通系统再打开 LW 文档对照着逐段修订——把文档里的项目名称、页面截图、数据库表名、核心代码注释改成你手上真实存在的版本。换句话说LW 是“给自己答辩用的半成品”不是拿去直接打印的完稿。如果你拿到的压缩包里没有 LW 文档也可以去看 README 或者 docs 目录。有些作者会把设计说明以 README 的形式写在项目根目录里内容虽然简单但至少能帮你快速定位后端端口号、数据库名、默认账号这些关键启动信息。“完整源码 LW”的本质是一个可以复现的项目而不是一本光读不练的教材。3. 把项目跑起来导入微信开发者工具到调出首页的完整路径3.1 环境准备工具版本与账号类型怎么选在解压 zip 之前先把运行环境准备好。微信开发者工具建议选择“稳定版”而不是“开发版”。如果你的源码里用了比较新的基础库 API比如wx.setBackgroundFetchToken、wx.getSkyInfo一个不支持该 API 的基础库版本会让你在控制台看到一堆报错。稳定版的小程序基础库一般在 2.3x 以上覆盖绝大多数毕设项目够用了如果包里有 npm 依赖或使用了第三方 UI 组件库还需要先在终端执行npm install再在开发者工具里点击“工具 → 构建 npm”。这一步极易被忽略症状是页面空白但控制台没有明显报错。后端如果按 Spring Boot 来准备需要 JDK 1.8 或 11很多旧源码在 JDK 17 上会启动失败是因为 Lombok 版本过旧或 Tomcat 版本不兼容以及 Maven 3.6 以上、MySQL 5.7/8.0。注意 MySQL 8.0 和 5.7 的驱动配置写法不同8.0 要求在 URL 上加useSSLfalseserverTimezoneAsia/Shanghai驱动类名要用com.mysql.cj.jdbc.Driver。老源码默认写的com.mysql.jdbc.Driver在 MySQL 8 下会直接启动报错这也是一个高频坑具体会在第 5 章展开。账号类型方面在开发者工具里可以用测试号或自己的小程序 AppID 导入项目。测试号免注册、速度最快适合第一次跑通如果要真机预览或调试登录接口则必须用自己注册的小程序 AppID个人主体即可申请。这里提醒源码里很可能写死了原作者的 AppID你导入后要在project.config.json里改成自己的测试号或 AppID否则真机预览时会提示“没有该小程序的使用权限”。3.2 导入项目的标准步骤从解压到页面渲染拿到“基于小程序的上门维修系统源码小程序毕业设计完整源码LW.zip”首先用解压工具解开路径尽量用英文且不要带空格例如D:\weixiu避免中文路径引起开发者工具解析异常。打开微信开发者工具 → 导入项目 → 选择解压后的小程序前端目录。这里存在一个最常见的误操作很多同学把整个压缩包解压后的根目录当作项目目录导入。但毕设源码通常包含frontend或miniprogram和backend或server两层结构正确目录应该是有app.js、app.json、pages/的那一层。选错目录的典型症状是项目列表能看到文件但模拟器里一片空白提示“app.json 文件未找到”。导入成功后先不要急着点预览。打开app.js或config.js找到后端接口地址的配置项。以最常见的 config.js 为例通常是这样的写法// config.js module.exports { // 后端服务地址跑本地后端时用 localhost真机调试时改成电脑的局域网 IP baseUrl: http://127.0.0.1:8080, // 图片上传根路径很多毕设图片是直接传回本地目录的 uploadUrl: http://127.0.0.1:8080/file/upload }这段代码的逻辑说明baseUrl是所有小程序端 wx.request 请求的前缀。模拟器里可以直接用127.0.0.1因为模拟器和电脑共享网络但如果你点击“真机调试”手机上的小程序无法访问你电脑的环回地址必须把这里改成电脑在局域网中的 IP例如http://192.168.1.101:8080并且手机和电脑要在同一个 WiFi 下。uploadUrl同理它专门用于图片上传走的是wx.uploadFile不能和业务接口混用一个地址。参数说明127.0.0.1只是本地开发的最小配置它能跑通不代表它在任何网络环境都可用。当你用真机预览时必须检查电脑防火墙是否允许 8080 端口对局域网开放否则后端日志显示收到了请求小程序端却一直转圈。如果你把后端部署到云服务器则需要把baseUrl换成 HTTPS 域名并且必须在小程序后台“开发管理 → 服务器域名”里把该域名加到 request 合法域名列表。很多源码默认给的是 IP 或 http 协议这在线上环境必然被拦截。3.3 后端服务的启动链路数据库初始化、接口连通后端启动的第一步是建库。打开 SQL 脚本文件通常头部会有CREATE DATABASE或DROP TABLE IF EXISTS的语句。建议使用命令行或 Navicat 按顺序执行脚本注意脚本里如果指定了utf8mb4字符集而你的 MySQL 默认不是建表后中文可能出现乱码但直接执行大多数情况下没问题。然后打开后端工程找到application.yml或application.properties。这是后端启动前必须核对的核心文件常见的需要改动的位置如下# application.yml 核心配置 server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/weixiu_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 你的数据库密码 driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true这里的逻辑说明server.port决定后端暴露的端口它必须和小程序 config.js 里的baseUrl端口一致。jdbc:mysql后面的weixiu_db是数据库名要与你前面执行的 SQL 脚本里 CREATE DATABASE 的名称一致。serverTimezoneAsia/Shanghai解决了国内服务器与 MySQL 的时区偏差如果不加你可能会看到订单创建时间比真实时间早 8 小时的诡异现象。map-underscore-to-camel-case: true这一项值得单独解释。数据库字段通常是下划线风格create_timeJava 实体类习惯用驼峰createTime。开启这个配置后MyBatis 映射时自动“下划线与驼峰互相转换”不会查不到值。如果你的源码没开这个配置且后端代码里写的 SQL 是select *那么返回给前端的 JSON 里字段名可能是create_time而不是createTime前端取数据时res.data.createTime就会拿到 undefined。这是“接口返回正常但页面不显示数据”的一大来源。启动后端时在项目根目录执行mvn spring-boot:run如果你的机器没装 Maven也可以使用项目自带的mvnwMaven Wrapper脚本Windows 下用mvnw.cmd spring-boot:run。看到日志里出现“Started Application in x.xxx seconds”就说明后端启动成功。接着不要急着回小程序端先做一次接口连通测试浏览器地址栏访问http://127.0.0.1:8080/api/order/list如果能返回 JSON 数据说明数据库连接和接口映射都是好的。此时回微信开发者工具刷新首页的“在线报修”“师傅列表”等模块应当能正常渲染。如果首页能出来、但列表数据为空优先去浏览器直接访问对应接口确认是后端没查到数据还是小程序的wx.request没把数据传回页面。这一步能帮你把问题快速定位到“前端 bug”还是“后端 bug”而不是在两边反复猜。4. 从用户下单到师傅接单核心流程怎么改才像你自己做的4.1 用户端报修单提交表单校验与图片上传跑通项目只是第一步答辩时老师一定会问“这个流程你是怎么实现的”。用户提交报修单是最核心的链路通常包含选服务类型、填地址、选预约时间、上传照片几个动作。你要能对着代码讲清楚“表单参数如何收集、如何传参、后端如何处理”。先看前端报修页面核心代码大致长这样// pages/repair/repair.js 中提交方法的核心片段 submitOrder() { if (!this.data.serviceType) { wx.showToast({ title: 请选择服务类型, icon: none }) return } if (!this.data.address.trim()) { wx.showToast({ title: 请填写上门地址, icon: none }) return } // 组装提交给后端的字段注意字段名要和后端实体类对应 const orderData { userId: wx.getStorageSync(userId), serviceType: this.data.serviceType, appointmentTime: this.data.appointmentTime, address: this.data.address, description: this.data.description.trim(), imageUrl: this.data.uploadedImage || , // 初始状态0 表示待派单 status: 0 } wx.request({ url: getApp().globalData.baseUrl /api/order/create, method: POST, data: orderData, success: (res) { if (res.data.code 200) { wx.showToast({ title: 下单成功 }) wx.redirectTo({ url: /pages/order/list?status0 }) } } }) }这段代码的逻辑说明前端在提交前做了两次校验——服务类型和地址不能为空这是一个必要的健壮性处理。由于用户的 openid 通常在登录时已经换成了后端签发的 userId因此这里从本地存储里读取而不是每次重新获取。提交时显式带上status: 0值得注意它让新订单直接进入“待派单”状态是由前端定义的业务起点。参数说明imageUrl字段是图片路径来源于 wx.uploadFile 上传后的返回结果不是本地临时路径。这里有一个新手常犯的错把wx.chooseMedia拿到的临时路径直接存进数据库结果后端回显时图片已经失效。正确链路是先用wx.uploadFile上传到后端后端返回可访问的 URL再把这个 URL 提交给订单接口。图片上传部分的代码示例// 上传图片到后端成功后把 URL 保存到页面 data 中 chooseAndUpload() { wx.chooseMedia({ count: 1, mediaType: [image], sourceType: [album, camera], success: (res) { const tempFilePath res.tempFiles[0].tempFilePath wx.uploadFile({ url: getApp().globalData.uploadUrl, filePath: tempFilePath, name: file, success: (uploadRes) { // 后端返回的是 JSON 字符串需要 parse 后取图片 url const data JSON.parse(uploadRes.data) this.setData({ uploadedImage: data.url }) } }) } }) }逻辑说明wx.chooseMedia返回的是临时文件路径它只能在当前会话内访问因此必须在success回调里发起wx.uploadFile将图片内容传到后端。name: file参数要求与后端接口的RequestParam(file)保持一致如果你的后端用的是MultipartFile image这里要相应改成name: image否则后端会直接报 400。4.2 师傅端“加载更多”列表与订单状态流转师傅端页面常见的是“待接单列表”这里有一个高频功能微信小程序页面列表加载更多。如果你在源码里看到onReachBottom方法那就是翻页加载的入口。这个功能不仅是业务需要也是答辩时很容易被追问的细节小程序列表是否需要一次性全部加载答案显然是否定的数据量上来之后一次性渲染全部订单会造成页面卡顿。常见实现方式如下// pages/worker/orders.js 中分页加载的核心代码 page: 1, pageSize: 10, loading: false, hasMore: true, loadOrders() { if (this.loading || !this.hasMore) return this.loading true wx.request({ url: getApp().globalData.baseUrl /api/order/pending, method: GET, data: { page: this.page, pageSize: this.pageSize }, success: (res) { const list res.data.rows this.setData({ orders: this.data.orders.concat(list) }) // 返回数量小于 pageSize 说明没有更多数据了 if (list.length this.pageSize) { this.hasMore false } else { this.page 1 } }, complete: () { this.loading false } }) }, // 页面滚动到底部时自动触发 onReachBottom() { this.loadOrders() }这段代码的逻辑说明page和pageSize控制翻页的起始位置和每页数量。loading是一个“开关锁”防止用户在慢网络下来回滚动时触发重复请求造成列表数据错乱。hasMore用于提前终止请求当后端返回的条数不足一页时说明已经到底此时再触发onReachBottom也没有意义。concat而不是赋值是保证旧数据不丢失只在尾部追加新一页的内容。参数说明pageSize设成 10 只是常见选择不是硬性规定。如果你在做答辩演示时想快速展示分页效果可以把pageSize改成 3 或 5这样多滑几次就能看到新一页数据加载演示效果更直观。真实场景里还需在onReachBottom前加“防重复点击”源码里如果没有这段逻辑你要能自己补上这也属于答辩时的加分项。订单状态流转本质就是在“待派单 → 已接单 → 维修中 → 已完成”之间做状态值的变更。师傅端点击“接单”时的代码一般是// 师傅接单操作 acceptOrder(e) { const orderId e.currentTarget.dataset.id wx.showModal({ title: 确认接单, content: 接单后将自动关联到你的账号, success: (res) { if (res.confirm) { wx.request({ url: getApp().globalData.baseUrl /api/order/accept, method: POST, data: { orderId, techId: wx.getStorageSync(techId) }, success: (res) { if (res.data.code 200) { this.setData({ currentTab: ongoing }) this.loadOrders() } } }) } } }) }需要说明的是接单操作不能直接修改订单状态必须先校验该订单是否仍处于“待派单”。如果两个师傅同时点击接单同一个订单后执行的请求应该得到“该订单已被接走”的提示。这就是后端接口里加UPDATE repair_order SET status 1 WHERE id ? AND status 0的原因——用数据库行锁来保证并发安全。源码中如果没有这个条件你在答辩前应当把它补上否则在并发演示时可能暴露数据一致性问题。4.3 管理后台派单逻辑把“自动派单”改成手动派单的切入点大部分毕设源码的管理后台都是“自动派单”或“管理员分配师傅”的简单逻辑。也就是说用户在服务类型里选了“水管维修”后台按师傅上架的服务类型匹配自动把订单挂到某个师傅名下。但如果你希望这个项目看起来更有“定制感”一个简单的做法是改造成“后台手动派单”在管理员订单列表里增加一个“指定师傅”按钮弹窗选择空闲师傅。这个改造的切入点是后端order的更新接口。你不需要重写整个模块只需复用一个通用接口把“自动分配师傅”的逻辑注释掉改成从前端接收techId// OrderAdminController.java 中派单接口的调整 PostMapping(/api/order/dispatch) public Result dispatch(RequestBody DispatchDTO dto) { // 注释掉原自动匹配逻辑 // Integer techId techService.autoMatch(dto.getServiceType()); // 改为使用前端传入的指定师傅ID Integer techId dto.getTechId(); if (techId null) { return Result.error(请选择要派单的师傅); } orderService.dispatch(dto.getOrderId(), techId); return Result.success(); }这段代码的逻辑说明后端原逻辑里autoMatch方法负责按服务类型自动匹配师傅这是很多毕设源码默认的“智能派单”。改造为手动派单后管理员在小程序管理端或 Web 管理后台选中订单并从下拉列表中选择一个空闲师傅然后把orderId和techId一起通过 POST 请求提交给后端接口。后端只需增加一个“师傅不能同时接两单”的校验就完成了整个派单闭环。必须注意的改造点手动派单要保证师傅 ID 在提交前处于“空闲”状态否则会出现“一个师傅接到两个同时段订单”的数据冲突。如果需要更健壮可以在tech_user表加一个current_order_id字段师傅一旦接单就写入当前订单 ID订单完成时置空。这样能避免由于派单时间重叠导致师傅重复上门。这个改进虽然只有几步但答辩时讲出来会让老师觉得你考虑到了真实业务约束。5. 七个常见坑为什么别人的源码在你电脑上总翻车5.1 白屏与大写的“app.json文件未找到”现象导入项目后模拟器一片白下方控制台出现app.json: 文件未找到或Error: 未找到 project.config.json。原因选错了导入目录。毕设源码往往是一个主目录下同时有微信小程序前端和后端项目开发者工具需要的只是前端那一层包含app.json、pages/的目录。如果你把整个 zip 解压后的根目录直接导入工具找不到入口文件。解决重新用开发者工具导入路径精确到包含app.js和app.json的那一层。你也可以先看压缩包内层文件名一般是miniprogram、frontend或直接就是一个小程序工程名。确认project.config.json和app.js在同一级即可。5.2 后端启动失败Driver 类和时区报错现象mvn spring-boot:run执行后控制台提示Loading class com.mysql.jdbc.Driver. This is deprecated随后抛出Access denied for user ...或SQLException: The server time zone value ... is unrecognized。原因MySQL 8.x 的驱动类从com.mysql.jdbc.Driver改成了com.mysql.cj.jdbc.Driver且连接 URL 必须显式声明时区如果源码是按 MySQL 5.x 时代写的新环境必报错。同时你本地 MySQL 的 root 密码与application.yml里不一致也会停在“Access denied”。解决把driver-class-name修改为com.mysql.cj.jdbc.Driver并在 URL 末尾追加useSSLfalseserverTimezoneAsia/Shanghai。username/password改成你自己数据库的真实账号密码。改完后重启。如果不确定密码是否写错可以先在命令行mysql -u root -p试连一次。5.3 模拟器能请求接口真机预览全部请求失败现象微信开发者工具里页面数据正常加载但点击“真机调试”后所有列表空白、请求超时。原因真机上的小程序运行在你的手机里无法通过http://127.0.0.1:8080访问到电脑上的后端。模拟器共享电脑网络所以能通手机不在电脑内部自然访问不到 loopback 地址。此外安卓手机会把127.0.0.1理解成手机自身iOS 同理。解决把config.js中的baseUrl从127.0.0.1改成你电脑的局域网 IP例如http://192.168.1.5:8080。可用ipconfigWindows或ifconfigmacOS查询。同时在电脑防火墙放行对应端口或开发时临时关闭防火墙。提交代码前记得改回服务器 IP 或域名。5.4 request 合法域名校验真机一调接口就报“不在以下合法域名列表中”现象点击页面按钮发起请求后真机直接弹出url not in domain list模拟器里却一切正常。原因微信规定小程序真机环境下wx.request的 URL 必须使用 HTTPS且域名需要在小程序后台配置为合法域名。毕设源码给的通常是http://127.0.0.1:8080或局域网 IP天然不具备配置条件。解决如果只是为了演示可以在微信开发者工具中勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”位于“详情 → 本地设置”。这个选项只对当前项目有效但它能让你在真机调试模式下继续使用 http 访问本地后端。如果论文答辩要求真机演示临时点击该选项是最稳妥的方案。5.5 页面列表只有第一页滚到底部不再加载现象页面首次进入能看到 10 条数据但滚动到底部后始终停留在第一页没有加载第二页。原因onReachBottom没有正确触发或者触发后page没有被递增导致每次请求都是第 1 页。也可能是hasMore被错误置成 false如果后端返回的字段名不是rows前端list.length判断会失效代码里误以为“没有更多”。解决先在模拟器里滚动页面的控制台查看onReachBottom是否执行。如果执行了但列表不追加检查data.page的初始值和请求后的递增位置。如果你的后端分页返回是data.list/data.total则必须在success回调里按实际字段名取列表。此外确认loading锁在complete回调里被释放否则第一次请求完成后锁没解开后续滚动全被if (this.loading || !this.hasMore) return拦截。5.6 订单创建时间晚 8 小时或直接变成 1970 年现象订单列表里显示的时间与本地时间相差 8 小时甚至所有时间都显示为1970-01-01。原因后端 JDBC 连接串没有指定serverTimezoneMySQL 的会话时区与 Java 进程时区不一致或者前端拿到的时间戳是秒级而 JavaScript 的new Date(timestamp)需要毫秒级。解决先按 5.2 的方法把serverTimezoneAsia/Shanghai加上如果时间戳类型不对在前端获取时间时做一次判断若长度是 10 位秒级乘以 1000 再new Date。排查时先看后端接口返回的原始 JSON是2025-01-01 10:00:00这样一个字符串还是一条长数字再决定改后端序列化格式还是前端展示层。5.7 图片上传成功但回显不出来现象上传图片时提示成功但页面里图片一直是裂开的打开控制台发现图片 URL 是http://127.0.0.1:8080/upload/a.png。原因前端把图片路径存成了“本地绝对路径”但该路径没有映射到后端的静态资源目录或者路径里写死了上传者的电脑 IP。如果有两个同学共用同一个源码A 上传的图片路径带着 A 的 IP在 B 的电脑上自然加载不出来。解决把图片存储路径改成相对路径例如/upload/a.png同时后端配置静态资源映射Spring Boot 工程中把本地目录映射到/upload/**路径。这样只要后端启动图片就能通过baseUrl /upload/a.png访问不会因为 IP 不同而失效。如果源码把上传路径写死成http://127.0.0.1改成config.js里的baseUrl拼接避免跨机器迁移后图片“失踪”。6. 答辩前夜用三条检查清单让源码真正“长在你身上”6.1 以答辩视角做一次全链路功能验收与其反复翻阅源码不如在答辩前按“讲师视角”走一遍系统全链路。一个人坐在电脑前打开后端日志窗口打开微信开发者工具从头开始操作新用户登录 → 提交报修单 → 管理后台派单 → 师傅接单 → 模拟维修完成 → 用户评价。每一步都写下来对应到代码文件路径。这样当老师问“这个订单状态是谁改的”时你能直接说出点击哪个按钮、调用哪个接口、更新了哪张表的哪个字段。做一个简单的验收表会有帮助验收场景操作路径预期结果用户注册登录小程序端授权登录后端拿到 openid生成 userId提交报修单选服务类型/填地址/传图片订单表新增记录status0后台派单管理员指定师傅订单 tech_id 更新status1师傅接单师傅端点击“接单”该订单不在待接单列表出现订单完成师傅点击“完成维修”订单 status3用户可评价用户评价评分文字order_comment 表新增记录验收中如果发现“用户评价后订单状态没有变”大概率是因为评价接口返回成功但前端没有刷新页面这是页面生命周期的问题而不是数据问题修复时只需在success回调里重新调用loadOrders()即可。6.2 两个耳熟能详的小优化顶部导航栏高度与动态标题答辩演示时最显眼的是小程序顶部的导航栏。用 iPhone 和安卓真机同时演示时如果发现自定义导航栏按钮被状态栏遮挡说明源码没有做“顶部导航栏高度”的适配。这也是近期很多同学在调试小程序页面布局时遇到的真实高频问题。正确的统一封装方式是使用“胶囊按钮”的位置计算小程序导航栏高度// utils/navbar.js 获取顶部导航栏高度与适配值 const getNavbarInfo () { const menuRect wx.getMenuButtonBoundingClientRect() const sysInfo wx.getSystemInfoSync() // menuRect.bottom胶囊按钮底部到屏幕顶部的距离 // sysInfo.statusBarHeight状态栏高度 const navBarHeight (menuRect.top - sysInfo.statusBarHeight) * 2 menuRect.height return { statusBarHeight: sysInfo.statusBarHeight, navBarHeight: navBarHeight } }这段代码的逻辑说明自定义导航栏时的经典公式是“状态栏高度 导航栏内容高度”。wx.getMenuButtonBoundingClientRect返回胶囊按钮的几何信息状态栏高度通过wx.getSystemInfoSync获取。两个值组合就能算出与胶囊按钮完全对齐的导航栏高度避免开发者在不同机型上反复调 padding。使用方式在页面的onLoad里调用getNavbarInfo()再把statusBarHeight绑定到页面数据的padding-top上即可让自定义标题栏在任何机型下保持一致。部分源码是“自定义导航栏”和“原生导航栏”混用的当你从原生导航栏跳到自定义导航栏页面时如果不做这个适配视觉上会出现明显跳动。另一个答辩时很加分的细节是“小程序动态设置标题”。比如从列表点进不同订单时让标题变成“订单号20250101001”而不是固定不变的“订单详情”。只需要一行// 订单详情页动态标题 wx.setNavigationBarTitle({ title: 订单号 orderId })这个 API 必须在onLoad拿到orderId之后执行才能让导航栏在页面加载时即显示新标题。如果放在onReady里可能出现“旧的标题闪一下再变化”的视觉瑕疵。配合导航栏高度适配这套前端细节能让老师看出你对小程序 API 的熟练程度。6.3 一次跑通之后的习惯给源码建立你自己的“修改地图”我的习惯是跑通项目后的第一天就在项目根目录建一个CHANGE_LOG.md记录所有改动哪怕只是改了一个端口号。比如这样# CHANGE LOG 1. 将 application.yml 数据库密码改为本地 root 密码 2. 修改 config.js baseUrl 为局域网 IP 3. 在 OrderApiController 中新增手动派单接口 4. 修复师傅接单并发时的重复接单问题增加 status0 条件 5. 前端用户评价后刷新订单列表这个文件不需要多长但它能让你在三天后回看项目时立刻知道哪些代码是自己改的、哪些是原作者写的。答辩时如果被问“项目里有哪些地方是你修改的”你甚至可以直接打开变更日志逐条讲。这与临时抱佛脚地背代码形成了本质区别——后者一被追问就露怯前者能让老师感受到你是真的把源码跑通、吃透并且做出了自己的优化判断。每个变更日志项后面再加一行“为什么改”就更好了。比如“新增 status0 条件是因为两个师傅同时接单会导致数据覆盖。” 这实际上就是答辩时最能打动人的技术细节表达方式。久了你会发现所谓“基于源码做毕业设计”并不是把别人的代码换个名字交上去而是让它经过你的手之后变成一个你能随时说出“这里为什么这样设计”的系统。这套源码的方向没有错只要你按照上面几章从导入、跑通到改动再到最后的验证流程走一遍它就能成为一份真正经得起追问的毕设作品。过程中遇到任何一个报错先按第 5 章的清单对照大多数问题都在那七条里。希望帮到你。本文还有配套的精品资源点击获取
返回列表