ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

智慧物业微信小程序源码:缴费报修访客登记完整前端工程

智慧物业微信小程序源码:缴费报修访客登记完整前端工程

简介:这是一套面向小区业主、业委会与物业三方协同场景的智慧物业微信小程序完整源码,适合具备一定小程序开发基础、希望快速搭建社区服务平台的开发者参考。它针对物业事务繁杂、业主加班难跑腿的痛点,把报修报检、重大事项投票、活动报名、公告通知、业委会公示及租售信息查询等功能集中到线上,免去往返物业中心的麻烦。资源包共559个文件,以js业务逻辑、wxss样式、wxml页面结构、json配置为主,另含png、jpg等图片素材与说明文档,压缩包约8.4MB,采用腾讯小程序云开发方案,无需自备服务器和域名。目前已有193人学习下载。读者可从中获得前后端完整代码、云开发数据调用思路与页面组织方式,便于二次开发或作为社区类小程序的学习范本。

1. 智慧物业微信小程序源码:一套能跑通缴费、报修、访客登记的完整前端工程

如果你正在接社区或园区数字化的小活,大概率绕不开一个需求:业主打开微信就能缴费、报修、叫访客通行。这套智慧物业微信小程序源码,就是围绕这三条主线搭起来的前端工程,包含页面结构、组件封装、接口请求层和本地模拟数据。它适合两类人:一类是刚接私活、需要快速交付一个能演示的物业端小程序;另一类是想拆解小程序工程化写法、看看真实业务页面怎么组织的中级开发者。源码本身不绑定后端,接口层做了统一封装,你换成自己的服务地址就能联调。下面按“先看懂结构、再动手跑起来、最后避开几个高频翻车点”的顺序拆一遍,中间会给出关键配置和代码片段,照着改就能复现。

2. 工程结构与技术选型:为什么用原生小程序而不是跨端框架

2.1 目录分层与页面职责

拿到源码先别急着改,花十分钟把目录过一遍,后面改起来才不迷路。这套工程采用原生小程序结构,没有引入 uni-app 或 Taro,原因是物业类小程序页面数量有限、交互不复杂,原生方案在包体积和启动速度上更稳,也省去跨端编译的玄学问题。核心目录大致是这样:

  • pages/下按业务拆分:index(首页聚合)、pay(缴费)、repair(报修)、visitor(访客)、mine(个人中心)
  • components/放复用组件,比如card、empty、step-bar
  • utils/放请求封装request.js、格式化工具format.js、常量config.js
  • mock/放本地模拟数据,方便没后端时先跑通页面

每个页面基本遵循index.js / index.json / index.wxml / index.wxss四件套。index.json里声明usingComponents和导航栏标题,index.js里管data、生命周期和事件。理解这个分层后,你要加一个新页面,就是复制一套四件套、在app.json的pages数组里注册路径,再在utils/config.js里补接口地址。

2.2 请求层封装与配置项

原生小程序直接调wx.request会写得很散,这套源码在utils/request.js里做了一层 Promise 封装,统一处理 baseURL、超时、错误提示和 token 注入。关键代码长这样:

// utils/request.js const config = require('./config.js') function request(options) { return new Promise((resolve, reject) => { wx.request({ url: config.baseURL + options.url, // 统一拼接域名 method: options.method || 'GET', data: options.data || {}, header: { 'content-type': 'application/json', 'Authorization': wx.getStorageSync('token') || '' // 登录后写入 }, timeout: 10000, // 超时 10 秒,物业接口普遍不快 success(res) { if (res.statusCode === 200 && res.data.code === 0) { resolve(res.data.data) } else { wx.showToast({ title: res.data.msg || '请求失败', icon: 'none' }) reject(res.data) } }, fail(err) { wx.showToast({ title: '网络异常', icon: 'none' }) reject(err) } }) }) } module.exports = request

逻辑说明:config.baseURL是唯一需要你改的地方,指向自己的服务地址;code === 0是这套源码约定的成功码,如果你的后端用200表示成功,把判断改掉即可。参数上,timeout设 10 秒是因为物业缴费接口常要查第三方账单,设太短容易误报失败。Authorization从本地缓存取,登录页写入 token 后,后续请求自动带上,不用每个页面手动传。

2.3 本地模拟数据怎么切换

没有后端时,mock/目录下的数据文件可以直接被页面引用。切换方式是改utils/config.js里的一个开关:

// utils/config.js module.exports = { baseURL: 'https://your-domain.com/api', // 换成你的服务地址 useMock: true // true 走本地模拟,false 走真实接口 }

页面里判断useMock决定是require模拟数据还是调request。这个设计的好处是演示阶段不用等后端,先把页面和交互跑通,联调时把开关一关就行。注意模拟数据的字段结构要和真实接口保持一致,否则切换时会冒出一堆undefined。

3. 缴费与报修模块:从页面交互到接口联调的完整链路

3.1 缴费页的账单渲染与支付调用

缴费是物业小程序里最核心也最容易出问题的模块。这套源码的缴费页分两块:账单列表和支付按钮。账单数据从接口拉取后,按status字段区分“待缴”和“已缴”,渲染时用wx:if控制按钮显隐。核心逻辑如下:

// pages/pay/index.js const request = require('../../utils/request.js') Page({ data: { billList: [], total: 0 }, onLoad() { this.fetchBills() }, fetchBills() { request({ url: '/property/bills', method: 'GET' }) .then(list => { const total = list .filter(item => item.status === 'unpaid') .reduce((sum, item) => sum + item.amount, 0) // 汇总待缴金额 this.setData({ billList: list, total }) }) .catch(() => {}) }, onPay(e) { const billId = e.currentTarget.dataset.id request({ url: '/property/pay', method: 'POST', data: { billId } }) .then(res => { // res 里应包含 wx.requestPayment 所需参数 wx.requestPayment({ timeStamp: res.timeStamp, nonceStr: res.nonceStr, package: res.package, signType: 'MD5', paySign: res.paySign, success: () => { wx.showToast({ title: '缴费成功', icon: 'success' }) this.fetchBills() // 重新拉取刷新状态 }, fail: () => { wx.showToast({ title: '支付取消', icon: 'none' }) } }) }) } })

逻辑说明:fetchBills拉取账单后,用filter加reduce算出待缴总额,避免在 wxml 里做复杂计算。onPay先请求后端下单接口,拿到支付参数再调wx.requestPayment。参数上,signType常见是MD5或HMAC-SHA256,要和后端签名方式一致,不一致会报“支付签名验证失败”。支付成功后重新拉账单,而不是本地改状态,防止和后端数据不一致。

3.2 报修工单的表单校验与图片上传

报修模块的难点在表单校验和图片上传。源码里报修页包含报修类型选择、描述输入、图片上传三部分。图片上传用wx.chooseImage加wx.uploadFile,先传到文件服务拿到 URL,再随工单一起提交。关键片段:

// pages/repair/index.js Page({ data: { typeIndex: 0, types: ['水电', '门窗', '电梯', '其他'], desc: '', imgList: [] }, chooseImage() { wx.chooseImage({ count: 3, // 最多 3 张,物业工单够用 sizeType: ['compressed'], // 压缩图,省流量 success: res => { this.setData({ imgList: this.data.imgList.concat(res.tempFilePaths) }) } }) }, submit() { if (!this.data.desc.trim()) { wx.showToast({ title: '请填写问题描述', icon: 'none' }) return } // 先上传图片,再提交工单 const uploadTasks = this.data.imgList.map(path => { return new Promise((resolve, reject) => { wx.uploadFile({ url: 'https://your-domain.com/api/upload', filePath: path, name: 'file', success: res => resolve(JSON.parse(res.data).url), fail: reject }) }) }) Promise.all(uploadTasks).then(urls => { return request({ url: '/property/repair', method: 'POST', data: { type: this.data.types[this.data.typeIndex], desc: this.data.desc, images: urls } }) }).then(() => { wx.showToast({ title: '提交成功', icon: 'success' }) wx.navigateBack() }) } })

逻辑说明:count: 3限制图片数量,避免用户传十几张导致上传超时。sizeType: ['compressed']用压缩图,物业场景不需要原图。提交时先用Promise.all并发上传所有图片,拿到 URL 数组后再提交工单,保证工单里存的是可访问的图片地址而不是本地临时路径。参数上,name: 'file'要和后端接收字段名一致,不一致后端收不到文件。

3.3 访客登记与通行码生成

访客模块相对轻,核心是生成一个带时效的通行码。源码里用时间戳加随机数拼一个码,展示在页面上,同时提交给后端记录。这里要注意的是通行码的有效期,常见做法是设 24 小时,过期后页面提示失效。实现上,onLoad时请求后端生成码,页面用setInterval倒计时刷新剩余时间,离开页面时clearInterval,否则会内存泄漏。

4. 避坑与排查:这套源码落地时最容易翻车的五个点

4.1 域名未配置导致请求全部失败

现象:真机预览时所有接口报“网络异常”,开发者工具里却正常。原因:小程序正式环境要求请求域名在后台白名单里,开发者工具可以勾选“不校验合法域名”绕过,真机不行。解决:把baseURL的域名加到小程序后台的 request 合法域名列表,注意必须是 HTTPS,且不能带端口号(除非是 443)。

4.2 支付签名参数对不上

现象:调wx.requestPayment报“支付签名验证失败”。原因:后端签名用的signType和前端传的不一致,或者timeStamp类型不对(有的后端返回数字,小程序要求字符串)。解决:确认前后端signType统一,timeStamp用String()转一下,package字段格式是prepay_id=xxx,别漏了前缀。

4.3 图片上传后路径失效

现象:工单提交成功,但详情页图片打不开。原因:上传接口返回的是临时路径,或者前端把tempFilePaths直接存进了数据库。解决:上传接口必须返回可长期访问的 URL,前端提交前确认拿到的是这个 URL 而不是本地临时路径。常见做法是上传后JSON.parse(res.data)取url字段。

4.4 setData 频繁调用导致页面卡顿

现象:账单列表滚动时明显掉帧。原因:在循环里频繁setData,或者一次setData的数据量过大。解决:把多次setData合并成一次,列表渲染用wx:key指定唯一字段,避免整个列表重绘。数据量大时考虑分页加载,别一次性渲染几百条。

4.5 本地缓存 token 过期未处理

现象:用户登录一段时间后,所有接口报 401,但页面没跳登录。原因:请求层没处理 401 状态码,token 过期后直接失败。解决:在request.js的success里判断statusCode === 401,清除本地 token 并跳转登录页。这个逻辑要放在统一封装里,别每个页面写一遍。

5. 进阶技巧:用分包和骨架屏把首屏体验拉起来

源码默认是单包结构,页面一多主包体积容易超限。小程序主包限制 2MB,物业类项目加上图片资源很容易顶到上限。进阶做法是把报修、访客这类非首屏页面拆到分包里,主包只留首页、缴费和个人中心。配置在app.json里加subpackages字段,每个分包声明root和pages。拆完后主包体积能降三成左右,启动速度肉眼可见变快。

另一个技巧是骨架屏。物业首页要等接口返回才能渲染,白屏时间长了用户会以为卡死。源码里首页预留了骨架屏结构,接口返回前显示灰色占位块,返回后替换成真实内容。实现方式是用一个loading状态控制wx:if切换,骨架屏的 wxml 就是几个灰色view加animation做呼吸效果。这个改动不大,但演示时观感提升明显。

验证分包是否生效,可以在开发者工具的“代码依赖分析”里看主包和分包体积。验证骨架屏,把useMock关掉、接口故意延迟几秒,看首页是不是先出灰块再出内容。这两个点做完,这套源码的完成度就够拿去给客户演示了。从那以后我每次拿到小程序源码,都先跑一遍分包体积分析和首屏白屏时间,这两个指标不过关,后面功能写得再全也白搭。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进