更新记录
1.0.1(2026-10-21)
这个模板解决什么问题
社区团购、驿站代收普及后,「最后一公里到门口」这一段一直是断的:驿站 21:00 关门,上班族 19:00 才到家;老人搬不动大件;下雨天不想下楼。
平台兼容性
云端兼容性
| 支付宝云 | 腾讯云 | 阿里云 |
|---|---|---|
| × | × | √ |
uni-app(5.32)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | √ | √ | √ | √ | - | √ | - | - | - | - | - |
云函数类插件通用教程
使用云函数类插件的前提是:使用HBuilderX 2.9+
邻里代取 · 社区驿站代取互助小程序
一套可直接运行的社区跑腿完整项目模板:同一个小区的邻居互相帮忙,把包裹从驿站捎到门口,发单人付服务费,接单邻居赚劳务费。
uni-app(Vue 3)+ uniCloud 阿里云,只做微信小程序端,全云对象架构,零第三方 UI 库,15 张表(11 在用)、6 个云对象、1 个定时函数、14 个页面。
- 前端 25 个
.vue(约 8500 行)+ 15 个.js(约 1200 行) - 云端 20 个
.js(约 2400 行)+ 16 份 schema / 初始化数据 - 不依赖 uni-ui、uView、colorui 等任何 UI 库,所有组件自建(
easycom,yd-前缀)
一、这个模板解决什么问题
社区团购、驿站代收普及后,「最后一公里到门口」这一段一直是断的:驿站 21:00 关门,上班族 19:00 才到家;老人搬不动大件;下雨天不想下楼。
模板把这件事做成了一个双边市场:
- 发单人:选小区 → 选驿站 → 填取件码 → 付服务费 → 等邻居送上门
- 接单邻居:认证 → 上线 → 大厅抢单 → 到驿站取件(上传凭证)→ 送达(上传凭证)→ 拿钱
因为只服务单个小区(communityId 贯穿全表),供需密度足够高,3 分钟内就能匹配到人,这是它和全城跑腿平台的根本区别。
二、功能清单
2.1 已实现(开箱可用,无需改代码)
账号与小区
| 功能 | 说明 | 位置 |
|---|---|---|
| 微信登录 | code 换 openid,首次登录自动建档 |
yd-user.loginByWeixin |
| 会话令牌 | 自签 HS256 JWT(Node 原生 crypto,零依赖、不落库),默认 30 天 | yd-common/token.js |
| 协议门 | 登录页必须勾选《用户协议》《隐私政策》才可点登录 | pages/login |
| 手机号 | 手动输入 11 位并格式校验,选填;AES-256-GCM 加密存 phoneEnc,对外只给 138****8000 |
yd-user.bindPhone |
| 修改手机号 | 「我的」页 → 手机号 → 修改 | pages/login?forcePhone=1 |
| 资料编辑 | 昵称 + 微信头像(chooseAvatar) |
pages/user/mine |
| 小区绑定 | 关键字搜索 / 定位按距离排序 / 绑定即生效 | yd-base.searchCommunity |
| 换小区 | 「我的」页 → 当前小区 | pages/user/community |
下单与支付
| 功能 | 说明 | 位置 |
|---|---|---|
| 服务目录 | 服务名、图标、描述、计价规则、抽佣比例全部由云端下发 | yd-base.config |
| 驿站选择 | 只能选本小区下的驿站 | yd-base.stations |
| 地址簿 | 增删改查、设默认、楼栋/单元/门牌 | yd-address.* |
| 取件码 | 入库前 AES-256-GCM 加密,仅接单方可解密;订单列表只给末 2 位 | yd-order.create + detail |
| 计价 | 基础 + 超重(5/10kg 两档)+ 加急 + 夜间(21:00–08:00)+ 悬赏 | yd-common/pricing.js |
| 下单 | 生成订单号、地址快照、写截止时间、状态 PENDING_PAY |
yd-order.create |
| 支付 | 记账式 mock 支付(mockPay=true 时下单即标记已付),订单立即进大厅 |
yd-pay.create |
| 取消 | 未接单全额退;已接单扣 30% 补偿接单方;已取件不可取消 | yd-order.cancel |
| 确认收货 | 确认后把 riderIncome 打进接单方钱包 |
yd-order.confirm |
| 评价 | 1–5 星 + 标签 + 文字,一单一评,写 reviews 表 |
yd-order.rate |
接单与履约
| 功能 | 说明 | 位置 |
|---|---|---|
| 实名认证 | 姓名 + 18 位身份证号,通过后获得 rider 角色 |
yd-user.submitCert |
| 上线 / 下线 | 上报位置,驱动大厅轮询与空态提示 | yd-rider.setOnline |
| 抢单大厅 | 本小区、待接单、排除自己发的单、先发先看 | yd-rider.hall |
| 抢单原子性 | 条件更新(状态 + 小区 + 非本人),影响行数=1 才算抢到 | yd-rider.accept |
| 抢单失败归因 | 分别返回 OWN_ORDER / COMMUNITY_MISMATCH / ORDER_TAKEN / STATE_INVALID / NOT_FOUND |
yd-rider.explainAcceptFailure |
| 取件 | 必须上传 1–3 张驿站存证照片,写 pickupDeadlineAt |
yd-rider.pick |
| 送达 | 必须上传 1–3 张交接存证照片,写 confirmDeadlineAt |
yd-rider.deliver |
| 门牌号保护 | 未取件前接单方看不到门牌,取件后才下发完整地址 | yd-order 视图层 |
| 双向存证 | 发单方与接单方都能回看双方上传的照片 | pages/order/detail、pages/rider/task |
结算、信用与兜底
| 功能 | 说明 | 位置 |
|---|---|---|
| 钱包 | 余额、累计收入、累计提现(展示用)、流水明细 | yd-common/wallet.js |
| 乐观锁 | 钱包更新带 version,并发不丢账 |
wallet.js |
| 收益统计 | 完成单数、评分、信用分、总收入 | yd-rider.stats |
| 信用分 | 取件超时扣 5 分,初始 100 | yd-common/sweep.js |
| 定时兜底 | 每 5 分钟扫一次,四条规则见下文 | yd-task + sweep.js |
| 幂等 | 四条扫描规则全部「条件更新 + 带原状态」,重复扫描不会重复打款 | sweep.js |
工程与体验
| 功能 | 说明 | 位置 |
|---|---|---|
| 设计令牌 | uni.scss 单一来源($yd-*),禁止硬编码色值 |
uni.scss |
| 图标 | 内联 SVG data-uri,Lucide 风格,单色描边 | components/yd-icon |
| 自建组件 | 导航栏、步骤条、价格、标签、空态、加载、动作面板、订单卡、隐私弹窗 | components/yd-* |
| 统一请求层 | 页面 → api/* → utils/request.js,统一错误提示 + 登录失效回登录页 |
utils/request.js |
| 登录态同步 | 云端拒绝 token 时同时清 storage 与 Pinia 内存态,避免页面互弹死循环 | App.vue + EVENT.AUTH_EXPIRED |
| 隐私合规 | 隐私授权弹窗 + chooseImage / getLocation 拦截兜底,绝不静默挂起 |
utils/privacy.js + yd-privacy |
| 无 UI 库 | 不引入任何第三方 UI,样式全部走 $yd-* 变量 |
全局 |
2.2 未实现(需要你自己接,代码里已留好位置)
| 功能 | 现在的状态 | 你需要做什么 | 改造位置 |
|---|---|---|---|
| 真实微信支付 | mockPay=true,下单即视为已支付,不产生任何真实资金流 |
开通商户号 → 实现 v3 JSAPI 下单与回调验签 → mockPay=false |
yd-pay/index.obj.js 里标了 TODO 的分支 |
| 退款 | 只改 payments 表状态为 REFUNDED,没有调微信退款接口 |
调 /v3/refund/domestic/refund |
yd-common/payment.js、yd-pay.refund |
| 提现 | 钱包页点「提现」弹「功能开发中」,withdraws 表有 schema 无代码 |
微信商家转账到零钱 + 提现审核 + 手续费 | 新建 yd-withdraw 云对象 |
| 订阅消息 | 6 处 TODO,无模板 ID,用户只能靠下拉刷新看到进度 |
后台申请模板 → 前端 requestSubscribeMessage → 云端 subscribeMessage.send |
yd-order.cancel、yd-rider.accept/pick/deliver 等 |
| 接单认证审核 | 提交即通过,无身份证真伪核验 | 接三要素核验 API,或改为 PENDING 走人工审核 |
yd-user.submitCert 里 TODO |
| 信用分权益 | 只有扣分,没有「低于 60 分禁止接单」的拦截(认证页规则里却写了) | 在 accept 前加信用分判断 |
yd-rider.accept |
| 申诉 / 争议 | complaints 表有 schema,没有云对象、没有入口(取消时文案提到「发起申诉」) |
申诉云对象 + 冻结资金 + 后台处理 | 新建 yd-complaint |
| 管理后台 | 无。改配置只能进 uniCloud 控制台改数据库 | uniCloud admin 或自建 Web 后台 | — |
| 评价时追加打赏 | rate 里 tipAmount 固定写 0 |
接支付后再开放 | yd-order.rate |
| 地图 / 导航 | 无地图组件,地址只有文字 | 接 <map> + openLocation |
订单详情页 |
| 骑手距离 | hall 里 distance 恒为 null(注释写明需联表驿站坐标) |
驿站表加坐标 + 距离计算 | yd-rider.hall |
2.3 刻意不做(设计取舍,不是漏了)
- 不做承运:不生成面单、不做干线运输,只做「驿站 → 家门口」这一段
- 不用微信分账:本场景接单方要拿 85%,微信分账上限 30%,因此资金模式是「平台自营 + 众包劳务」
- 不做押金:用信用分替代,避免资金池合规问题
- 不做全城调度:一个小区一个池子,不做跨小区派单
- 不做实时聊天:站内不设 IM,靠备注 + 客服电话
- 文案禁用「快递 / 运费」:统一说「代办服务 / 服务费」,避免被认定为快递经营
三、技术架构
【微信小程序端】uni-app Vue3 + Pinia
pages/*.vue 14 个页面 —— 只调 api/*,不直接 importObject
↓
api/*.js 5 个文件,薄封装
↓
utils/request.js 统一错误 toast / token 失效清本地态 / 防抖跳转
↓ uniCloud.callFunction
────────────────────────────────────────────
【uniCloud 阿里云】
云对象 6 个 yd-base yd-user yd-address yd-order yd-rider yd-pay
云函数 1 个 yd-task(定时触发器,每 5 分钟)
公共模块 2 个 yd-common(业务内核)、uni-config-center(配置中心)
↓
云数据库 15 张表(permission 全 false,只有云端能读写)
云存储(存证照片、头像)
3.1 为什么全走云对象
不用 clientDB / JQL,所有读写都在云对象里:
schema的permission全部写false,客户端无法直连数据库,越权面为零- 金额、状态机、抽佣、加密全部在服务端,客户端拿不到密文和手机号
- 代价是每个业务方法都要写一遍参数校验,换来的是不会被前端改价
3.2 目录结构
├── App.vue 全局事件监听(登录失效、小区失效)
├── main.js Pinia 挂载
├── manifest.json ⚠️ 本模板已清空 appid,导入后请填自己的
├── pages.json 14 个页面 + 4 个 tabBar
├── uni.scss 设计令牌(颜色/字号/间距/圆角)唯一来源
├── api/ 接口层:address common order rider user
├── common/constants.js 前端常量镜像(订单状态、错误码、事件名、时限默认值)
├── components/ 10 个自建组件,全部 yd- 前缀
│ ├── yd-icon/icons.js 内联 SVG 图标表
│ ├── yd-privacy/ 隐私授权弹窗
│ └── yd-order-card/ 接单大厅订单卡
├── pages/
│ ├── index/ 首页:进行中订单 + 服务入口
│ ├── login/ 登录 + 手机号(支持 forcePhone 改号)
│ ├── order/{create,list,detail}/
│ ├── rider/{hall,task,wallet}/
│ ├── user/{mine,address,cert,community}/
│ └── common/webview/ 协议 / 隐私政策
├── static/ logo + 4 组 tabBar 图标
├── store/ user.js(登录态)config.js(服务目录/计价/时限)
├── utils/
│ ├── request.js 云对象调用 + 错误处理 + 401 回登录
│ ├── privacy.js 隐私授权(主动询问 + 拦截兜底)
│ ├── format.js 金额/时间/距离/时长格式化
│ ├── order.js 状态文案、颜色、步骤条
│ ├── pickup.js 取件码解析与校验
│ └── auth.js 登录态判断
├── scripts/pack-market.py 打包到插件市场(清 appid、清密钥、去 unpackage)
└── uniCloud-aliyun/
├── cloudfunctions/
│ ├── common/yd-common/ 业务内核(11 个文件)
│ │ ├── token.js 自签 HS256
│ │ ├── auth.js 验签 + 读用户 + 角色判断
│ │ ├── crypto.js AES-256-GCM
│ │ ├── pricing.js 计价
│ │ ├── timeout.js 时限解析(读 service_catalog)
│ │ ├── wallet.js 钱包(乐观锁 + 流水)
│ │ ├── payment.js 支付流水
│ │ ├── sweep.js 四条超时兜底
│ │ ├── resp.js 统一响应
│ │ ├── geo.js 地理工具
│ │ └── constants.js 状态机与业务常量
│ ├── common/uni-config-center/ 配置中心(yd/config.json)
│ ├── yd-base/ yd-user/ yd-address/ yd-order/ yd-rider/ yd-pay/
│ └── yd-task/ 定时任务
└── database/ 15 张表 schema + 索引 + db_init.json(种子数据)
3.3 分层铁律
- 页面只调
api/*,绝不直接uniCloud.importObject - 云对象只通过
yd-common共享逻辑,彼此不互相调用 - 每个云对象都在自己的
package.json里平铺声明file:../common/xxx依赖(uniCloud 不递归解析) - 金额一律用「分」存整数;时间一律用时间戳
- 云端与前端的常量两份(
common/constants.js↔yd-common/constants.js),改动必须同步
四、数据模型
4.1 15 张表(11 张在用 + 4 张仅 schema)
| 表 | 用途 | 状态 |
|---|---|---|
users |
用户、角色、认证状态、信用分、手机号密文 | ✅ 在用 |
addresses |
收货地址,含小区归属 | ✅ 在用 |
communities |
小区(含坐标) | ✅ 在用 |
stations |
驿站(归属小区) | ✅ 在用 |
service_catalog |
服务目录:计价规则、抽佣、时限 | ✅ 在用 |
orders |
订单主表 | ✅ 在用 |
payments |
支付流水 | ✅ 在用(记账式) |
wallets |
钱包余额、版本号 | ✅ 在用 |
wallet_transactions |
资金流水 | ✅ 在用 |
reviews |
评价 | ✅ 在用 |
rider_shifts |
接单方上线状态与位置 | ✅ 在用 |
withdraws |
提现申请 | ⚠️ 仅 schema,无代码 |
complaints |
申诉仲裁 | ⚠️ 仅 schema,无代码 |
audit_logs |
审计日志 | ⚠️ 仅 schema,无代码 |
configs |
动态配置 | ⚠️ 仅 schema,无代码(配置已改由 uni-config-center 承载) |
db_init.json 覆盖 12 张表(withdraws / complaints / audit_logs 无种子数据)(含 3 个小区 + 3 个驿站 + 1 条服务目录种子数据)。
4.2 订单状态机
PENDING_PAY ──支付──> PENDING_ACCEPT ──抢单──> ACCEPTED ──取件──> PICKED ──送达──> DELIVERED ──确认/自动──> COMPLETED
│ │ │
└──取消/超时关单──> CANCELLED <──取消(扣30%补偿)┘
│
无人接单超时 ──> CANCELLED + 退款
↓
REFUNDED(资金态)
DELIVERING 为预留中间态(当前不写入)、DISPUTED 为申诉态(未实现)。
取消规则:PENDING_PAY / PENDING_ACCEPT 全额退;ACCEPTED 扣 riderIncome × 30% 补偿接单方;PICKED 之后不可取消。
4.3 订单上的四个截止时间
| 字段 | 何时写入 | 作用 |
|---|---|---|
payDeadlineAt |
下单时 | 超时未支付自动关单 |
acceptDeadlineAt |
支付成功时 | 超时无人接单自动取消并退款 |
pickupDeadlineAt |
接单时 | 超时未取件 → 退回大厅 + 扣 5 分信用分 |
confirmDeadlineAt |
送达时 | 超时未确认 → 自动确认并结算 |
设计要点:截止时间写死在订单上,不是每次现算。这样后台调整时限只影响新订单,不会把已经挂在厅里的订单的承诺时间改掉。
五、计价与分账
阶段一只有一个服务:FETCH(驿站代取)。规则在 service_catalog.pricingRule:
{
"base": 250, // 基础服务费 2.50 元
"weightStep1": 100, // 5–10kg 加 1.00 元
"weightStep2": 300, // >10kg 再加 3.00 元(叠加 step1)
"urgent": 200, // 加急加 2.00 元
"night": 200 // 夜间(21:00–08:00)加 2.00 元
}
计算(全部整数分):
总额 total = base + weightSurcharge + urgentSurcharge + nightSurcharge + tip
平台费 platformFee = round(total × commissionRate) // commissionRate 默认 0.15
骑手收入 riderIncome = total − platformFee
例:基础单、非夜间、不加急、无悬赏 → total=250,platformFee=38,riderIncome=212(骑手拿 84.8%)。
⚠️ 注意:当前实现里
platformFee是按含悬赏的总额计提的,而下单页文案写的是「悬赏全额给到接单邻居,平台不抽成」。若要让悬赏不抽佣,把pricing.js第 49 行改成Math.round((total - tip) * rate)即可。这是产品决策,模板保留原样未改。
六、时限与超时兜底
6.1 可调时限
全部在 service_catalog 的 timeout 字段,改数据库即生效,不用发版、不用重启:
"timeout": {
"payMinutes": 5, // 待支付关单
"acceptMinutes": 1440, // 无人接单自动退款 = 1 天
"pickupMinutes": 120, // 接单后取件时限 = 2 小时
"confirmMinutes": 120 // 送达后自动确认 = 2 小时
}
字段缺失、填 0、填非数字都会回落到默认值(yd-common/constants.js 的 TIMEOUT_DEFAULT)。
6.2 四条兜底规则
yd-task 每 5 分钟跑一次 yd-common/sweep.js:
| 超时 | 处理 |
|---|---|
待支付超过 payMinutes |
关单(未付款不涉及退款) |
待接单超过 acceptMinutes |
取消 + 自动退款 |
已接单超过 pickupMinutes 未取件 |
订单退回大厅重新派单,接单方扣 5 分信用分 |
已送达超过 confirmMinutes 未确认 |
自动确认 + 结算打款给接单方 |
四条都用「条件更新 + 带原状态」写库,与用户/骑手操作并发时以数据库结果为准,重复扫描不会重复结算。
七、安全与隐私
| 手段 | 实现 |
|---|---|
| 取件码 | AES-256-GCM 加密存 pickupCodeEnc,仅接单方可解,列表只给末 2 位 |
| 手机号 | 加密存 phoneEnc,任何接口只返回 138****8000 |
| 门牌号 | 未取件前接单方只看到「楼栋+单元」,取件后才下发门牌 |
| 身份证 | 加密存储,接口永不回传明文 |
| 越权 | schema.permission 全 false,客户端无法直连 DB;云对象逐方法校验 userId / riderId |
| 抢单并发 | 条件更新影响行数判定,禁止「先查再写」 |
| 钱包并发 | version 乐观锁 + 流水表 |
| 会话 | 自签 HS256,30 天有效;UNAUTHORIZED 一律清本地态并回登录页 |
| 隐私合规 | manifest.__usePrivacyCheck__=true;utils/privacy.js 主动询问 + 拦截兜底,任何分支都必须给出结果(被拦下的接口既不报错也不继续,resolve 漏掉就是「点了没反应」) |
八、快速开始(7 步跑通)
前置
- HBuilderX 3.8+(建议最新版)
- 已实名认证的 DCloud 账号
- 阿里云 uniCloud 服务空间(免费版即可跑通)
- 微信小程序 AppID(个人主体也可,但手机号快捷登录 / 位置类目受限时需企业主体)
1. 导入项目并关联云空间
HBuilderX → 文件 → 导入 → 从本地目录导入 → 选中本项目 → 右键 uniCloud-aliyun → 关联云服务空间或项目 → 选一个阿里云空间。
2. 填配置
编辑 uniCloud-aliyun/cloudfunctions/common/uni-config-center/yd/config.json:
{
"wxAppId": "你自己的微信小程序 AppID",
"wxAppSecret": "你自己的 AppSecret",
"cryptoKey": "64 位十六进制随机串(AES-256 密钥)",
"tokenSecret": "64 位十六进制随机串(JWT 密钥)",
"tokenExpiresIn": 2592000,
"mockPay": true,
"serviceHotline": "客服电话,可留空",
"ruleText": "服务保障文案,展示在首页"
}
生成两个随机串:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
3. 上传公共模块(必须先做)
右键 uniCloud-aliyun/cloudfunctions/common/uni-config-center → 上传公共模块
右键 uniCloud-aliyun/cloudfunctions/common/yd-common → 上传公共模块
4. 初始化数据库
右键 uniCloud-aliyun/database/db_init.json → 初始化云数据库。
会建表、建索引,并写入 3 个测试小区 + 3 个驿站 + 1 条服务目录。
已有数据会被覆盖,生产库请在控制台手工建。
5. 上传云函数
依次右键上传(顺序不能反,函数打包时会把公共模块复制进自己的 node_modules):
yd-base → yd-user → yd-address → yd-order → yd-rider → yd-pay → yd-task
上传 yd-task 后到控制台确认「定时触发器」已创建(0 */5 * * * * *,每 5 分钟)。没自动创建就手动加一条。
6. 填 appid 并运行
manifest.json → 基础配置 → 重新获取 uni-app 应用标识(或填自己的)
manifest.json → 微信小程序配置 → 填自己的微信 AppID
HBuilderX → 运行 → 运行到小程序模拟器 → 微信开发者工具。
7. 小程序后台配置
- 开发管理 → 服务器域名:uniCloud 会自动加白,无需手工填
- 设置 → 服务内容声明 → 用户隐私保护指引:必须声明
- 手机号(若用手机号登录/展示)
- 相册(仅写入)+ 摄像头(上传取件/送达存证照片,不声明会 errno 112,上传按钮直接无反应)
- 位置信息(识别所在小区) 提交后约 5 分钟生效
- 设置 → 基本设置 → 服务类目:选「生活服务 > 跑腿代购」或当地可用类目
九、配置说明
9.1 uni-config-center/yd/config.json
| 字段 | 必填 | 说明 |
|---|---|---|
wxAppId |
✅ | 微信小程序 AppID,用于 jscode2session |
wxAppSecret |
✅ | 对应 AppSecret,只能放服务端 |
cryptoKey |
✅ | 64 位 hex,AES-256-GCM 加解密取件码/手机号/身份证 |
tokenSecret |
✅ | 64 位 hex,JWT 签名密钥 |
tokenExpiresIn |
✅ | token 有效期(秒),默认 2592000 = 30 天 |
mockPay |
✅ | true = 记账式支付(不产生真实资金流);接真实支付后改 false |
serviceHotline |
⬜ | 客服电话,留空则「联系客服」按钮提示未配置 |
ruleText |
⬜ | 首页「服务保障」文案 |
改了
config.json必须重新上传公共模块uni-config-center,再重传依赖它的云函数,否则云端读到的还是旧值。
9.2 service_catalog(业务参数,改库即生效)
| 字段 | 说明 |
|---|---|
pricingRule.base |
基础服务费(分) |
pricingRule.weightStep1 / weightStep2 |
超重附加(分) |
pricingRule.urgent |
加急附加(分) |
pricingRule.night |
夜间附加(分) |
commissionRate |
平台抽佣比例(0–1),默认 0.15 |
timeout.payMinutes / acceptMinutes / pickupMinutes / confirmMinutes |
四个时限(分钟) |
enabled |
服务开关 |
9.3 小区与驿站
communities 与 stations 两张表,一对一小区下有多个驿站。
⚠️ 小区没有驿站会导致下单报「驿站不存在」,新增小区时记得同步加驿站。
十、常见问题
Q:登录成功但页面不跳转?
A:多半是拿到空 token。本模板用 yd-common/token.js 自签,不碰 uni-id-users 集合,store.user.login() 里还有硬校验——拿不到 token 直接抛错,不会再静默失败。
Q:一直提示「请先绑定小区」,但已经选过了?
A:鉴权读的是数据库里的 users.communityId,不是本地缓存。若云端确实没写进去,request.js 收到 COMMUNITY_REQUIRED 会同时清本地缓存并跳选小区页,不会卡死。
Q:接自己的单提示「已被抢走」?
A:大厅已排除自己发的单,且 accept 失败时会回查真实原因(OWN_ORDER 会明确告诉你「不能接自己的单」)。要测完整流程请用**第二个*****(开发者工具 → 工具 → 多账号调试)。
Q:点「拍照上传」没反应?
A:隐私声明缺失(errno 112)或用户未同意。本模板已加 ensurePrivacyAuthorized 前置询问,并且失败必定有提示——看到「未声明相册/摄像头」就去小程序后台补声明。
Q:云函数报 resource exhausted?
A:不一定是额度用完。阿里云按「函数 × 小时」有最低消费,httpclient 默认 60 秒超时特别吃 GBs。本模板的 jscode2session 已显式设 timeout: 5000 并 try/catch。若仍报错,先看是不是空间被限制并发。
Q:改时限后旧订单没变? A:这是设计如此。时限在订单创建/支付/接单/送达时写死,改配置只影响新订单。
Q:mockPay=true 时为什么下单就显示已支付?
A:这是为了方便你先打通业务闭环。接真实支付时把 mockPay 置 false,yd-pay.create 会走虚拟支付分支(需你实现 v3 下单)。
十一、合规提示
- 文案禁用「快递」「运费」,统一叫「代办服务」「服务费」——本模板所有文案已按此约束
- 不做承运:不生成面单、不做分拣运输,只做同城末端捎带
- 资金模式:平台自营 + 众包劳务,不走微信分账(上限 30%,本场景要 85%)
- 不收押金:用信用分替代,避免资金池
- 上线前请按当地法规确认「跑腿/代取」类目的经营要求,以及是否需要为接单方投保
十二、源码加密(发布为付费插件时)
本模板是项目型插件(uniCloud 前后一体项目模板),加密配置放在项目根目录 package.json:
{
"uni_modules": {
"encrypt": ["uniCloud-aliyun/cloudfunctions/yd-order/index.obj.js", "utils/request.js"]
}
}
路径是相对项目根的真实文件路径。注意与 uni_modules 插件不同:项目根下的 uniCloud 目录带 -aliyun 后缀,写成 uniCloud/... 会静默失效。
已纳入加密的 33 个 js
| 范围 | 文件 |
|---|---|
| 云对象(6) | yd-base / yd-user / yd-address / yd-order / yd-rider / yd-pay 的 index.obj.js |
| 云函数(1) | yd-task/index.js(定时兜底) |
| 公共模块(12) | yd-common/*.js:计价、分佣、状态机常量、token、加密、钱包、sweep 等 |
| 前端(14) | api/*.js(5)、utils/*.js(6)、store/*.js(2)、common/constants.js |
不加密(平台限制或刻意保留)
| 文件 | 原因 |
|---|---|
pages/**/*.vue、components/**/*.vue |
平台不支持加密 vue/nvue,页面结构必然公开 |
manifest.json / pages.json / config.json |
JSON 不参与加密;config.json 还需使用者填自己的密钥 |
main.js |
入口文件保留明文,编译出错时好排查 |
components/yd-icon/icons.js |
纯 SVG 图标数据,无业务逻辑 |
uni-config-center/index.js |
配置加载器,使用者要能看到它如何读 config.json |
三件必须知道的事
- 加密只在付费插件生效:上传时普通授权版价格必须 > 0。免费发布的插件
encrypt配置会被忽略,源码照旧公开。 - 买家侧效果:普通授权版看不到加密文件,云函数试用期(一般 7 天)后才在买家空间上失效;授权绑定 appid + 包名,换一个就要重买;只有源码授权版拿到全部源码。
- 加密文件不能单独对外导出,所以不要把「准备给别的项目复用的库」放进
encrypt。
列表由脚本维护,别手抄:
python3 scripts/gen-encrypt.py # 重新生成(新增云对象/工具函数后跑一次)
python3 scripts/gen-encrypt.py --check # 只校验,不一致退出码非 0
python3 scripts/gen-encrypt.py --cloud-only # 降级:只加密云端,前端 js 恢复明文
pack-market.py 打包时会校验清单里每个路径在包内真实存在——路径写错不会报错,只会静默失效,这道检查就是防这个。
若买家反馈导入后编译失败(前端 js 加密依赖 HBuilderX 云端编译),用
--cloud-only重新出包即可:云函数照样加密,前端 js 退回明文。业务核心全在云对象里,前端开源不影响商业模式。
十三、版本
v1.0.1(versionCode 101)
- 完整业务闭环:登录 → 绑定小区 → 下单 → 支付(记账)→ 抢单 → 取件 → 送达 → 确认 → 结算 → 评价
- 四类超时兜底定时任务
- 隐私授权适配(主动询问 + 拦截兜底)
- 自签 token 取代 uni-id,零 uniCloud 官方依赖
后续计划(需要你自己实现,或看下一版):真实微信支付、退款、提现、订阅消息、认证审核、申诉仲裁、管理后台。
十四、许可
MIT。二次开发、商用均可,请自行承担合规与资金安全责任。

收藏人数:
购买源码授权版(
导入插件并试用
赞赏(0)
下载 861
赞赏 0
下载 35223
赞赏 159
赞赏
京公网安备:11010802035340号