简介:本资源为Discuz点微同城30.0全功能插件套件,专为基于Discuz! X平台构建本地化生活服务平台的开发者与运营方设计,覆盖同城分类信息、招聘、房产、婚恋、拼团、优惠抢购、小程序/H5前端等20余类高频业务场景,支持快速搭建具备完整商业闭环的同城生态站点。压缩包含2000个文件,主体为4117个PHP后端逻辑文件、2033个PNG图标与界面素材、1987个HTM/HTML页面模板及613个JS交互脚本,辅以CSS样式(256个)、WXSS/WXML小程序组件(共60余个)及SQL数据库结构,整体体积72.68MB,结构完整、模块解耦清晰,便于按需启用与二次开发。已有1403人学习下载。用户可直接部署全部47个官方插件(如同城教育培训、疫情地图、招聘PC版、会员卡等),获取开箱即用的前后端一体化解决方案,并通过大量weui.css、style.css等样式文件快速统一UI风格,显著降低定制化开发成本。
1. Discuz 点微同城 30.0 全套插件(47个)不是“一键安装包”,而是需深度适配 H5 与小程序双端的模块化扩展体系
Discuz 点微同城 30.0 这套标称含 47 个插件的集成方案,本质不是传统意义上的 Discuz 插件集合,而是一套围绕本地生活服务场景重构的、具备完整前后端协同能力的扩展架构。它把 Discuz 3.3+ 作为用户中心与内容底座,将门店管理、预约下单、LBS 推送、多端同步等能力拆解为可独立启用/禁用的插件单元,并强制要求 H5 页面与微信小程序必须共用同一套业务逻辑层(如订单状态机、优惠券核销规则、地理位置校验策略)。这意味着:哪怕你只启用其中 5 个插件,也必须完成 H5 端基于 WeUI.css 的样式重写、小程序端 wxs 与 WXML 的组件映射、以及两者共用的 API 接口签名机制。它解决的不是“论坛加功能”的问题,而是“如何让 Discuz 用户无缝切换到本地生活服务闭环”的工程落地问题——适合已有 Discuz 3.3 稳定站点、正启动社区 O2O 升级、且团队具备 PHP 后端 + Vue/UniApp 前端双栈能力的技术负责人或运维工程师。
2. 拆解点微同城 30.0 插件包结构:47 个插件按功能域分组,核心依赖项必须优先部署
点微同城 30.0 的 47 个插件并非平铺直列,而是存在明确的层级依赖关系。官方未公开文档,但通过实际解压discuz_plugin_dianwei_30.0.zip并分析install.php与config.php可确认其分为四类:基础支撑类(8 个)、LBS 服务类(12 个)、交易履约类(15 个)、多端桥接类(12 个)。其中,dianwei_core、dianwei_location、dianwei_api三个插件构成不可绕过的启动链——若未先启用它们,其余插件在 Discuz 后台插件列表中将显示为灰色不可用状态。
2.1 插件目录结构与启用顺序验证
解压后根目录下可见标准 Discuz 插件结构:
source/plugin/dianwei_* ├── dianwei_core/ # 必启:提供全局常量、数据库表注册、钩子注入入口 ├── dianwei_location/ # 必启:封装高德/腾讯地图 SDK 调用、地理围栏计算、坐标系转换 ├── dianwei_api/ # 必启:定义 /api/dianwei/ 下所有 REST 接口路由及 JWT 验签中间件 ├── dianwei_store/ # 依赖 core+location:门店信息管理 ├── dianwei_order/ # 依赖 core+api:订单创建与状态流转 └── ...(其余 44 个)提示:Discuz 后台启用插件时,若提示“插件依赖未满足”,不要直接点击“忽略依赖”,应进入
source/plugin/dianwei_core/install.php查看$dependency数组,确认缺失插件名。常见错误是误将dianwei_location启用在dianwei_core之前,导致class_location类未加载,后续所有地理相关插件初始化失败。
2.2 数据库表自动注册机制与手动补全要点
dianwei_core插件在首次启用时会执行discuz_plugin_dianwei_core::onInstall()方法,调用DB::query()创建 23 张新表(如pre_dianwei_store、pre_dianwei_order),并修改pre_common_setting表插入配置项。但实测发现:当 Discuz 主库字符集非utf8mb4_unicode_ci时,部分含 emoji 字段(如门店简介、用户评价)的建表语句会报错中断,导致pre_dianwei_user_address等 5 张表缺失。
此时需手动补全,执行以下 SQL(请替换pre_为你的实际表前缀):
-- 补全用户收货地址表(关键!H5 和小程序下单均依赖此表) CREATE TABLE `pre_dianwei_user_address` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `uid` int(10) unsigned NOT NULL DEFAULT '0', `name` varchar(50) NOT NULL DEFAULT '', `mobile` varchar(20) NOT NULL DEFAULT '', `province` varchar(50) NOT NULL DEFAULT '', `city` varchar(50) NOT NULL DEFAULT '', `district` varchar(50) NOT NULL DEFAULT '', `address` varchar(255) NOT NULL DEFAULT '', `longitude` decimal(10,7) NOT NULL DEFAULT '0.0000000', `latitude` decimal(10,7) NOT NULL DEFAULT '0.0000000', `is_default` tinyint(1) NOT NULL DEFAULT '0', `createtime` int(10) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `uid` (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;2.2.1 表字段设计逻辑说明
longitude/latitude使用decimal(10,7)是为兼容高德地图返回的 7 位小数精度坐标(如116.4809721),避免 float 类型存储导致的定位漂移;is_default为 tinyint(1) 而非 enum,因小程序端需通过UPDATE ... SET is_default=0 WHERE uid=?批量取消旧默认值,再设新值,enum 在批量更新时易触发 MySQL 严格模式报错;createtime存储 Unix 时间戳而非 datetime,与 Discuz 原生common_member表时间字段类型一致,便于跨表 JOIN 查询。
3. H5 端接入:基于 WeUI.css 构建响应式页面,重点解决定位权限与缓存一致性
点微同城 H5 端并非简单套用 Discuz 默认模板,而是以weui.css为视觉基底,通过独立入口/dianwei/h5/加载 Vue 2.6 单页应用。其核心挑战不在 UI 实现,而在微信浏览器环境下的定位授权链路与离线缓存策略冲突。
3.1 微信内嵌 H5 获取定位的三步校验流程
微信对wx.getLocation的调用有明确限制:必须在用户主动触发(如点击按钮)后才能调用,且需提前配置 JSAPI 安全域名。点微同城 H5 的实现路径如下:
- 预检 JSAPI 权限:在
main.js中调用wx.config(),传入后端生成的签名(签名算法需与dianwei_api插件中class_dianwei_api_sign完全一致); - 用户显式授权:页面加载后不自动获取定位,而是展示「开启位置服务」按钮,绑定
@click="getLocation"; - 降级兜底逻辑:若
wx.getLocation失败(如用户拒绝、iOS 15+ Safari 限制),则 fallback 到 HTML5 Geolocation API,并弹窗提示“将使用浏览器定位,精度可能较低”。
// utils/location.js export function getLocation() { return new Promise((resolve, reject) => { if (window.wx && typeof wx.getLocation === 'function') { // 微信 JSAPI 方式(高精度) wx.getLocation({ type: 'wgs84', // 返回 GPS 坐标,与高德地图 SDK 兼容 success: (res) => { resolve({ lat: res.latitude, lng: res.longitude }); }, fail: () => { // 降级到浏览器 API navigator.geolocation.getCurrentPosition( (pos) => resolve({ lat: pos.coords.latitude, lng: pos.coords.longitude }), (err) => reject(err) ); } }); } else { // 非微信环境直接走浏览器 API navigator.geolocation.getCurrentPosition( (pos) => resolve({ lat: pos.coords.latitude, lng: pos.coords.longitude }), (err) => reject(err) ); } }); }注意:
wx.config()的jsApiList必须包含'getLocation',且后端签名时使用的nonceStr、timestamp、url三元组需与前端请求 URL 完全一致(包括 query 参数),否则签名验证失败,wx.getLocation将静默不可用。
3.2 H5 页面缓存策略与 Discuz 登录态同步
点微同城 H5 采用service-worker+Cache API实现离线资源缓存,但带来新问题:Discuz 用户登录态(authcookie)在 service worker 中不可见,导致缓存页面无法携带登录凭证发起 API 请求。
解决方案是将登录态从 cookie 迁移至 localStorage + 请求头透传:
- 用户登录成功后,
dianwei_api插件返回access_token,前端存入localStorage.setItem('dwtoken', token); - 所有
/api/dianwei/请求在axios.interceptors.request中添加:config.headers.Authorization = 'Bearer ' + localStorage.getItem('dwtoken'); - 同时,在
service-worker.js的fetch事件监听中,对/api/dianwei/请求手动添加 header:event.respondWith( fetch(event.request.clone(), { headers: { 'Authorization': 'Bearer ' + localStorage.getItem('dwtoken') || '' } }) );
3.2.1 WeUI.css 与 Discuz 主题的样式隔离方案
WeUI.css 默认样式会污染 Discuz 原有.postcontent、.pl等类名。点微同城采用 CSS Modules 方案,在 Vue 组件中:
<template> <div class="dianwei-h5"> <weui-button @click="submit">提交</weui-button> </div> </template> <style module> .dianwei-h5 :global(.weui-btn) { border-radius: 4px; /* 覆盖 WeUI 默认 2px */ } </style>关键点::global()用于穿透作用域,确保 WeUI 组件样式生效;而外层.dianwei-h5保证不泄漏到 Discuz 全局。
4. 小程序端对接:UniApp 编译为微信小程序,重点处理 API 签名与动态标题
点微同城 30.0 的小程序前端基于 UniApp 开发,目标平台为微信小程序。其核心难点在于:如何让 UniApp 编译后的代码,复用 Discuz 后端已有的 JWT 签名体系,同时支持小程序原生能力(如wx.navigateToMiniProgram跳转其他小程序)。
4.1 UniApp 中复用 Discuz API 签名逻辑
Discuzdianwei_api插件生成的签名是 PHP 实现的 HMAC-SHA256,UniApp 需用 JavaScript 完全复现。关键参数包括:appid(固定为dianwei)、timestamp(秒级时间戳)、nonce(16 位随机字符串)、path(如/order/create)、body(JSON 字符串,需排序 key 后序列化)。
// utils/sign.js import CryptoJS from 'crypto-js' export function generateSign(params) { const { appid = 'dianwei', timestamp, nonce, path, body = '' } = params // 1. body 对象 key 排序后 JSON.stringify(Discuz 端使用 ksort + json_encode) const sortedBody = JSON.stringify( Object.keys(JSON.parse(body)) .sort() .reduce((obj, key) => { obj[key] = JSON.parse(body)[key] return obj }, {}) ) // 2. 拼接待签名字符串 const strToSign = `${appid}${timestamp}${nonce}${path}${sortedBody}` // 3. 使用 Discuz 后台配置的 secret_key 计算 HMAC const secretKey = uni.getStorageSync('dianwei_secret') || 'your-secret-key' return CryptoJS.HmacSHA256(strToSign, secretKey).toString(CryptoJS.enc.Base64) }提示:
secret_key不可硬编码在前端,应在小程序首次启动时,通过uni.login()获取 code,调用/api/dianwei/auth/init接口由后端返回加密后的密钥片段,再拼接成完整 secret。
4.2 小程序动态设置标题与顶部导航栏适配
点微同城小程序需根据当前页面(如门店详情页、订单支付页)动态设置标题,且需兼容 iOS/Android 不同状态栏高度。Discuz 原生不提供此能力,需在pages.json中关闭原生导航栏,改用自定义navigation-bar组件:
{ "path": "pages/store/detail", "style": { "navigationStyle": "custom", // 关键:禁用原生导航栏 "navigationBarBackgroundColor": "#ffffff", "navigationBarTextStyle": "black" } }然后在pages/store/detail.vue中:
<template> <view class="container"> <custom-nav-bar :title="storeName" :show-back="true" /> <!-- 页面内容 --> </view> </template> <script> export default { data() { return { storeName: '' } }, onLoad(options) { // 从 options 或 vuex 获取门店名,设置标题 this.storeName = options.store_name || '门店详情' } } </script>4.2.1 自定义导航栏组件实现要点
- 使用
uni.getSystemInfoSync().statusBarHeight获取状态栏高度,动态设置padding-top; - 左侧返回图标使用
uni.navigateBack(),右侧分享按钮调用uni.showShareMenu(); - 标题文字字号设为
17px(微信规范),颜色#333,避免使用font-weight: bold(iOS 渲染异常)。
5. H5 与小程序数据互通验证:通过订单号反查与地理位置校验双维度确认一致性
47 个插件的价值最终体现在 H5 与小程序用户行为数据的实时互通上。最典型的验证场景是:用户在 H5 页面下单后,能否在小程序“我的订单”中立即看到,且订单中的配送地址经纬度与 H5 端获取值完全一致?这需要从数据库和接口两个层面交叉验证。
5.1 订单号生成规则与跨端唯一性保障
点微同城订单号格式为DW{YMD}{6位随机数}{3位校验码},例如DW20240615123456789。其中:
{YMD}为当日日期(非时间戳),确保每日订单号空间独立;{6位随机数}由mt_rand(100000, 999999)生成,避免自增 ID 暴露业务量;{3位校验码}为crc32(订单主体JSON字符串) % 1000,用于防篡改。
验证方法:在 H5 下单后,立即查询数据库:
SELECT order_sn, longitude, latitude, createtime FROM pre_dianwei_order WHERE order_sn LIKE 'DW20240615%' ORDER BY createtime DESC LIMIT 1;再从小程序端调用/api/dianwei/order/list?uid=123,比对返回 JSON 中order_sn、address.longitude、address.latitude是否与数据库完全一致(注意:浮点数需保留 7 位小数比对)。
5.2 地理位置校验失败的典型日志定位
当 H5 与小程序订单地址偏差超过 500 米时,大概率是坐标系转换错误。点微后台日志中搜索关键词geo_convert_error,可定位到source/plugin/dianwei_location/function.php中的convert_coordinate()函数。该函数默认将微信返回的gcj02坐标转为wgs84,但若传入参数from='bd09'(百度坐标系),则转换结果失效。
修复方式:在 H5 端getLocation()成功回调中,明确指定坐标系:
wx.getLocation({ type: 'gcj02', // 强制要求微信返回国测局坐标系 success: (res) => { // 此时 res.longitude/res.latitude 为 gcj02,可直接传给后端 } });5.2.1 跨端数据一致性检查表
| 检查项 | H5 端来源 | 小程序端来源 | 数据库字段 | 一致性要求 |
|---|---|---|---|---|
| 用户 UID | localStorage.getItem('duid') | uni.getStorageSync('duid') | pre_dianwei_order.uid | 完全相等 |
| 订单创建时间 | Date.now()(毫秒) | Date.now()(毫秒) | pre_dianwei_order.createtime | 转换为秒后相等 |
| 门店 ID | URL 参数store_id=123 | options.store_id | pre_dianwei_order.store_id | 数值相等 |
| 配送地址经纬度 | res.latitude/res.longitude(gcj02) | e.detail.latitude/e.detail.longitude(gcj02) | pre_dianwei_order.longitude/pre_dianwei_order.latitude | 保留 7 位小数后字符串完全匹配 |
执行该表任一检查项失败,即表明 H5 与小程序未真正打通,需回溯dianwei_api插件的请求解析逻辑或dianwei_location的坐标入库逻辑。
本文还有配套的精品资源,点击获取