简介:全民经纪人小程序v2.3.95是一套面向房产中介行业的全开源微信小程序项目,包含前端小程序与后台管理端,适合需要搭建经纪人管理、房源展示、佣金结算体系的开发者或运营者参考复用。压缩包共1244个文件,大小仅6MB,涵盖png、js、html、json、wxss、wxml、php等类型,其中wxml/wxss/js构成小程序界面与交互,json负责配置,php提供后台服务端逻辑,png/gif等图片承载界面素材,整体目录清晰,便于按模块拆解学习。当前已有212人学习下载。本次版本重点优化了后台财务管理中佣金审核显示为0时的记录展示,并修复首页布局里的分享标题与分享图片问题,代码全开源,既可用于快速上线同类房产小程序,也可作为微信小程序+PHP后台开发的完整实战范例,尤其适合想了解房产分销业务与佣金审核流程的开发者。
1. 房产经纪佣金线上化,真正卡住的往往不是算法而是审核链路
做房产分销最头疼的不是房源展示,而是报备、带看、成交之后那笔佣金怎么算清楚。物业推荐业主、同行带客、自由经纪人注册推荐,来源角色一多,佣金为 0 的单子反而最容易出争议——后台过滤掉之后,财务对不上账,经纪人又投诉无门。v2.3.95 专门把“佣金为 0 的审核记录继续显示”这条补上了,配合首页分享标题与分享图片的修复,说明项目方是把审核闭环当成核心链路来维护的。
整套前端源码完全开源,样式上同时引用了 bootstrap.min.css、layui.css、jquery-ui-1.10.3.css 这类老牌库,前后端分离或整包私有化部署都能接。适合三种人:正在搭建微信小程序房产分销系统的技术团队、需要把自有 CRM 后台外卖出小程序端的前端开发,以及想研究佣金审核、分享配置这类典型业务流的开发者。后端接口服务可以用你们现有语言去接,前端这一侧本文直接照源码方案走。
2. 多套 UI 框架共存的样式分层:Bootstrap、layui 与 jQuery UI 的取舍
v2.3.95 的前端包里 CSS 数量不少,刚拿到手会觉得乱,实际拆开看是有明确分层的。这一章先把这堆样式文件按职责归档,再讲小程序渲染对它们的限制,最后给一个去掉 jQuery UI 依赖的拖拽方案,方便你要做二次改动时不至于被历史包袱绊住。
2.1 CSS 依赖的全景拆解
先用一张表把这批 css 按角色分清楚:
| 文件 | 职责 | 使用场景 |
|---|---|---|
| bootstrap.min.css | 栅格系统、基础 reset、按钮与表单底线 | 通用页面骨架、响应式布局 |
| layui.css | 后台表格、分页、弹层、表单控件 | 佣金审核列表、后台管理页 |
| weixin_head.css | 微信导航栏与胶囊按钮适配 | 小程序页面头部 |
| designer.css | 装修模式下拖拽占位、标线、选中态 | 首页布局编辑 |
| index_layout.css | 首页板块的网格对齐与间距 | 线上首页渲染 |
| jquery-ui-1.10.3.css | 拖拽排序、日期选择等交互样式 | 首页板块排序、筛选器 |
| font-awesome.min.css | 图标字体 | 全局功能图标 |
| _all.css | 业务组件叠加样式,覆盖上述库 | 列表、卡片、状态标签 |
常见做法是用 bootstrap 兜底全局,用 layui 承接管控类界面,再用一层业务 css 去覆盖细节。_all.css 命名很直白,就是放在最后加载的覆盖层,里面大量:not()和.layui-table-cell这类选择器,主要解决组件默认样式和业务预期不一致的问题。
2.2 小程序端渲染对 CSS 的限制
浏览器里那套样式规范在小程序里要做减法。bootstrap 的栅格用 rpx 转换后偏差不大,但 layui 依赖position: fixed的弹层在胶囊按钮下容易被遮挡,weixin_head.css 就是为这个写的。designer.css 里的:hover样式在触摸屏上不会触发,装修态建议用touchstart事件加 class 替代。
另一个坑是cover-view。首页如果用了地图组件,覆盖在上面的标题和按钮只能用cover-view渲染,font-awesome 的:before伪元素字符在里面不生效,要换成图片或 base64 图标。样式规范上建议只保留一至两个全局 css 文件,其余按页面拆,避免微信开发者工具对超过 100 KB 的单个样式文件做二次编译时卡顿。
2.3 去掉 jQuery UI 依赖的首页拖拽实现
首页布局编辑里jquery-ui主要负责板块拖拽排序。为了砍掉这个 300 多 KB 的依赖,可以直接用小程序原生触摸事件实现:
Page({ data: { blocks: ['banner', 'notice', 'hotList', 'brokerRank'], startIndex: -1 }, onTouchStart(e) { const index = e.currentTarget.dataset.index; this.setData({ startIndex: index }); }, onTouchMove(e) { const index = e.currentTarget.dataset.index; if (this.data.startIndex === -1 || index === this.data.startIndex) return; const blocks = this.data.blocks.slice(); const [moved] = blocks.splice(this.data.startIndex, 1); blocks.splice(index, 0, moved); this.setData({ blocks, startIndex: index }); }, onTouchEnd() { this.setData({ startIndex: -1 }); } });逻辑说明:splice先取出被拖动板块,再插入到目标位置,整个排列结果同步到data触发视图更新。参数说明:dataset.index是wx:for渲染时写入的原始索引,startIndex用来标记当前正在拖动的板块,防止touchmove重复触发时产生错位。
这套做法去掉了 jQuery UI 的样式和脚本依赖,排序结果直接绑定首页配置接口,保存时把blocks按顺序提交即可。
3. 佣金为 0 的审核记录在列表页与查询条件里的处理
v2.3.95 的更新点里写得很明确:“后台-财务管理-佣金审核-显示佣金为 0 时的审核记录”。这个需求拆成两端看:后端查询条件要放开过滤,前端列表要对 0 元单子做状态区分。很多人以为就是删一个where条件,实际上排序、展示、驳回交互都要跟着改。
3.1 从查询条件查起:零佣金记录为什么被默认过滤
佣金审核表的典型结构是经纪人 id、房源 id、审核状态、佣金金额、创建时间。常规列表查询为了不让空数据干扰审核员,习惯加上commission > 0,这就是 0 佣金记录被过滤的直接原因。物业推荐或未成交带看场景下,系统生成的记录佣金本来就应该为 0,但审核动作依然要走完,否则“已带看未成交”的数据链就断了。
调整后的查询逻辑:
SELECT id, broker_id, house_id, audit_status, commission, create_time FROM broker_commission_records WHERE audit_status = 0 AND deleted = 0 ORDER BY CASE WHEN commission = 0 THEN 1 ELSE 0 END, create_time DESC LIMIT #{offset}, #{pageSize}逻辑说明:去掉commission > 0条件,保留audit_status = 0(待审核)。排序里用CASE WHEN把 0 佣金记录放到列表末尾,避免影响审核员处理正常佣金单的效率。参数说明:offset和pageSize是分页参数,deleted = 0做软删除过滤,防止接口倒查时拿到脏数据。
如果后端是 MyBatis 体系,对应 mapper 里把<if test="commission != null">AND commission > 0</if>这段删掉即可。需要注意commission字段如果允许null,查询条件要写成IFNULL(commission, 0),否则 null 值记录一样会丢。
3.2 前端审核态与驳回交互的兼容逻辑
后端放开查询后,前端列表页的展示逻辑也要适配。佣金为 0 的单子在审核页不能再按普通佣金单渲染,金额区域显示0.00而不是隐藏,操作按钮要保留“通过”和“驳回”,避免审核员想点驳回时找不到入口。
function renderAuditList(list) { return list.map(item => { const zeroCommission = Number(item.commission) === 0; return { id: item.id, brokerName: item.brokerName, houseTitle: item.houseTitle, commission: Number(item.commission).toFixed(2), tagType: zeroCommission ? 'warning' : 'normal', tagText: zeroCommission ? '零佣金带看' : '待结算', canReject: true, rejectRequired: item.auditStatus === 0 }; }); }逻辑说明:Number(item.commission) === 0做严格判断,null会被转成 0,所以空佣金单也会归入零佣金分组。tagType控制标签颜色,零佣金用橙色弱化视觉权重,避免审核员误以为是高优单。参数说明:rejectRequired用于驳回弹窗,为零佣金单强制填写驳回理由,防止审核员随手驳回后财务这边没有解释依据。
这里的潜在问题:佣金字段如果是字符串"0.00",Number()转换不会出错,但如果带¥符号就会返回NaN,NaN === 0为false。所以接口层必须先去掉货币符号,或由后端返回纯数字字段。
3.3 排序与数据口径的边界
| 场景 | 原有逻辑 | 调整后 |
|---|---|---|
| 审核列表默认排序 | create_time DESC | 正常佣金优先,0 佣金置后 |
| 佣金金额显示 | 0 元直接隐藏 | 显示 0.00 并带状态标签 |
| 驳回理由 | 可选 | 零佣金单必填 |
| 导出报表 | 只含 > 0 记录 | 全量审核记录 |
调排序时注意,不要把 0 佣金单排序规则直接改成commission ASC,那样会把所有 0 元单顶到最前面,审核员最先看到的全是无佣金带看记录,反而漏掉真正要结算的单子。后台列表字段比较多,前端可以用wx:if控制“佣金”列渲染,但不要用wx:if把整条记录删掉,否则分页总数和后端对不上。
4. 分享标题与分享图片的动态设置:onShareAppMessage 改造实录
更新说明里第二条是“优化-首页布局-分享标题和分享图片问题”。这类问题十有八九出在配置读取时机和微信缓存上。首页布局由后台下发,分享标题和分享图片也来自后台配置,但小程序分享动作读取配置的时机经常早于接口返回,于是分享出去的就是默认标题和默认截图。
4.1 首页布局配置的下发格式
后台首页布局保存后,会生成一份 JSON 配置,前端启动时拉取并按板块渲染。常见结构:
{ "theme": "default", "share": { "title": "XX房产-金牌经纪人带你看好房", "imageUrl": "https://cdn.example.com/share/cover_v2.png", "path": "/pages/index/index?from=share" }, "blocks": [ { "type": "banner", "data": { "interval": 4 } }, { "type": "hotList", "data": { "limit": 6 } } ] }逻辑说明:share字段独立于blocks,这样首页板块渲染和分享配置互不影响。imageUrl固定走 CDN,不能填相对路径,也不能填本地assets下的图片。参数说明:path建议带from=share之类的标记,方便统计分享来源;theme字段用于切换首页配色,分享标题不随主题变化时前端不用重新请求配置。
4.2 setNavigationBarTitle 与 onShareAppMessage 联动
微信小程序的顶部导航栏标题和转发分享标题是两套逻辑,经常会遇到“导航栏标题改对了,分享出去还是旧标题”。原因是wx.setNavigationBarTitle只影响当前页面顶部显示,分享标题必须单独在onShareAppMessage里返回。
const app = getApp(); Page({ data: { shareConfig: { title: 'XX房产邀你看房', imageUrl: '/assets/share_default.png', path: '/pages/index/index' } }, onLoad() { this.loadHomeConfig(); }, async loadHomeConfig() { try { const config = await app.request('/api/home/config'); const share = config.share || {}; this.setData({ 'shareConfig.title': share.title || this.data.shareConfig.title, 'shareConfig.imageUrl': share.imageUrl || this.data.shareConfig.imageUrl }); wx.setNavigationBarTitle({ title: this.data.shareConfig.title }); } catch (e) { console.error('首页配置拉取失败,使用默认分享配置', e); } }, onShareAppMessage() { return { title: this.data.shareConfig.title, path: this.data.shareConfig.path + '&brokerId=' + app.globalData.brokerId, imageUrl: this.data.shareConfig.imageUrl }; } });逻辑说明:onShareAppMessage返回的title、path、imageUrl是转发时微信实际使用的三个字段。path里追加brokerId,好友点开分享卡片时前端从onLoad(options)里读取,用来绑定推荐关系。参数说明:imageUrl必须是 HTTPS 地址,且图片比例建议 5:4,实际渲染时会被裁成近似正方形,比例差异太大会出现内容截断。
这里有个并发隐患:用户进入页面后立刻点转发按钮,此时loadHomeConfig可能还没返回,分享出去的还是默认配置。处理办法是onShareAppMessage里不直接return,而是先判断配置是否加载完成,没完成则先返回默认值并再次拉取,下一轮分享自动更新。
4.3 分享图不更新的缓存坑与参数拼接
分享图片最常见的问题不是没传,而是 CDN 缓存导致改了图片微信那边还是旧图。微信对同一个imageUrl有较长的缓存时间,后台运营改了封面图,前端分享出去的仍是换图前的版本。
解决办法是在图片地址后面拼接版本参数:
function buildShareImage(rawUrl, version) { if (!rawUrl) return ''; const separator = rawUrl.indexOf('?') > -1 ? '&' : '?'; return `${rawUrl}${separator}v=${version}`; }逻辑说明:后台配置share时同步下发shareVersion字段,前端拼到imageUrl后面,CDN 会把带新参数的 URL 当成新资源回源。参数说明:version建议直接取后台配置更新时间戳,比如1720000000,不要用递增的小整数,避免 CDN 的忽略规则把 1、2、3 给吞掉。separator变量是为了兼容原来的 URL 已经带?参数的情况,避免拼出?a=1?v=2这种非法链接。
分享标题的长度也有讲究。微信内分享卡片标题最多显示 30 个字符左右,超过部分截断。房产场景标题建议控制在 16 字以内,比如“XX楼盘 经纪人王姐带看”,把楼盘名和经纪人放在前 8 个字,因为用户看到卡片时最先扫的就是这两个信息。
5. v2.3.95 上传发布与线上自检清单
代码改完要发布,v2.3.95 的发布流程和普通微信小程序版本一致,但这版涉及佣金审核和分享配置,上线前建议多走几步验证。
微信开发者工具里先做一次代码质量检查,确认没有wx.request域名未配置的告警。然后点击工具栏“上传”按钮,版本号填2.3.95,备注写“显示佣金为0审核记录+首页分享优化”。上传成功后登录微信公众平台,在“版本管理-开发版本”里找到刚上传的版本,点“选为体验版”,生成体验二维码。
体验版验证分两条线:
一是佣金审核链路。用测试账号走一遍“创建带看记录-产生 0 佣金单-后台审核”,确认列表中出现零佣金标签、点击驳回后必须填写理由、分页中零佣金单排列在正常佣金单之后。
二是分享链路。把首页配置里的分享标题改成测试文案,分享到文件传输助手,点开卡片检查标题、图片、跳转路径是否正确。分享两次以上,第二次分享前先把shareVersion参数改掉,确认 CDN 缓存没有命中旧图。
小程序后台还要检查“开发管理-服务器域名”里的request合法域名列表。常见错误是上线后接口请求全部失败,原因就是开发阶段勾选了“不校验合法域名”,发布后域名又没配。如果项目里用到了web-view嵌 H5,对应的业务域名也要一起配好,否则房源详情页加载不出来。两者配置生效有十几秒延迟,改完后刷两遍再测。
关于“扫码上传小程序发布”,微信开发者工具右上角有个真机预览的二维码,扫完是开发版,不是正式发布。正式发布必须在公众平台点“提交审核”,审核通过后点“全量发布”。v2.3.95 如果只做内部经纪人使用,可以提交审核时选“小程序内部体验”,理由填“仅限内部经纪人使用,需登录后才能访问”,审核会快一些。
最后分享一个验证分享缓存的小技巧:在开发者工具里打开“清缓存-清除全部缓存”,然后重新编译,分享后再回后台修改 shareVersion,这个过程走通基本能保证线上运营改图片时不会再来找前端。
本文还有配套的精品资源,点击获取