ARTICLE DETAIL

资讯详情

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

同城跑腿系统开发实战:Fastadmin+ThinkPHP与Uniapp三端搭建与避坑指南

同城跑腿系统开发实战:Fastadmin+ThinkPHP与Uniapp三端搭建与避坑指南 简介基于Fastadmin后台框架、ThinkPHP开发框架与Uniapp跨端工具开发的优创同城跑腿系统是一套面向跑腿团队、可私有化部署的全栈源码完整覆盖用户端、骑手端和运营后台适配帮取、帮送与同城配送场景。系统内置按距离、重量分类的计价规则支持临时加价、预约取件、骑手小费、物品保价以及地图精确选点并可一键抢单、按距离展示接单大厅、自由开关听单同时提供系统派单和智能派单两种模式兼有专职与兼职骑手佣金配置便于运营方灵活调整计价和调度策略。压缩包共2000个文件以1079个JavaScript脚本、265个HTML页面、235个Vue组件、213个JSON配置和142个Markdown文档为主另含CSS样式与SQL数据库初始化文件整体包体约43.97MB目录结构完整适合在已有Fastadmin或ThinkPHP实践经验的基础上进行二次开发。当前已有107人学习下载源码无加密可直接部署并继续扩展定制是搭建同城跑腿业务的高性价比技术方案。1. 从“帮取帮送”到三端闭环优创同城跑腿系统到底在做什么基于FastadminThinkPHP和Uniapp开发的优创同城跑腿系统听起来就是把“下单-接单-送达”搬到线上但真把用户端、骑手端、运营后台三个端跑起来很多团队才发现难的不是地图而是订单状态怎么流转、跑单费怎么算、异常订单谁来兜底。这套系统的核心业务是两类帮取到店代取、代买、排队和帮送文件、物品、钥匙。Fastadmin承担运营后台和接口底座ThinkPHP写API服务与任务调度Uniapp让用户端、骑手端用一套代码同时覆盖微信小程序与App。适合三类人准备上线跑腿业务的平台方想接同城订单的外包团队以及拿二开包做定制交付的开发者。这套组合的优势用一个词概括就是复用度高、落地快。2. 技术选型不是拍脑袋Fastadmin后台、ThinkPHP接口与Uniapp三端怎么各司其职2.1 为什么用FastadminThinkPHP做运营后台和API服务端Fastadmin底层跑的就是ThinkPHP那套MVC自带admin后台、权限菜单、CRUD一键生成对“后台管理大量列表少量业务表单”的项目非常省事。跑腿系统里要管的运营对象很多发单用户、骑手、商户、投诉、结算、公告放在Fastadmin里就是一组标准CRUD加几个自定义表格页面。常见做法是运营后台挂在application/admin模块对外API写在application/api模块两套共用同一份配置和数据库连接。这样部署时只跑一个站点登录鉴权、参数校验、日志组件都能复用。thinkphp项目运行起来也不复杂装好依赖、导入SQL、把public目录配成站点根目录再处理好伪静态基本就能跑。我一般会把站点根目录整理成下面这样方便后面讲清楚哪里改什么www.example.com/ # 站点根目录 ├── application/ │ ├── admin/ # Fastadmin运营后台控制器 │ ├── api/ # 用户端/骑手端请求的API模块 │ │ └── controller/ │ │ ├── Order.php # 下单、状态流转、取消 │ │ ├── Delivery.php # 骑手接单、取件、妥投、异常上报 │ │ └── User.php # 登录、余额、收货地址 │ └── config.php # 数据库、缓存、日志配置 ├── public/ │ ├── index.php # 前端入口nginx指向这里 │ └── uploads/ # 附件目录注意执行权限 ├── extend/ ├── runtime/ └── thinkphp/逻辑说明这个结构把后台管理和对外接口拆成两个模块但共用框架核心避免为同一套业务维护两套代码。api模块里每个控制器按业务域划分接口统一继承一个Base控制器统一做签名校验、token鉴权和参数过滤。参数说明你拿到的二开包如果api目录换了名字比如appapi迁移时记得同步改路由绑定否则后台页面能开但接口全404。Fastadmin的权限管理默认只覆盖admin模块api模块的token校验要自己写在Base控制器里。我习惯先在Base里检查请求头X-Token再查fa_user_token表过期自动续签和后台管理员的Auth互不干扰。这样用户在App里被冻结、骑手被停单同一个表就能体现出来。另外Fastadmin自带CRUD生成命令可以按数据表出一套控制器和视图php think crud -t order生成后修改listFields、addFields很快就能得到可用的订单管理页。2.2 Uniapp在用户端、骑手端里的角色一套代码三端打包跑腿系统的客户端有两个角色用户端下单、骑手端接单。你不可能为每个角色各写一个原生App所以Uniapp是最顺手的载体——同一套工程通过条件编译和manifest配置分别打出微信小程序和Android/iOS App。用户端和骑手端的业务差异我用一个环境常量区分// config/env.js 区分用户端与骑手端 const ENV { USER: user, // 用户端下单、支付、订单跟踪 RIDER: rider // 骑手端抢单、取件、妥投、余额提现 }; // 通过启动参数或本地缓存注入角色 const current uni.getStorageSync(client_type) || ENV.USER; // 公共请求头里带清楚角色身份 export function getHeaders() { return { client-type: current, X-Token: uni.getStorageSync(token) }; }逻辑说明两端共用一个代码仓库页面通过目录前缀区分比如用户端订单页放在user-order目录骑手端放在rider-order目录编译时只打包当前端需要的页面这样也为后面小程序分包打基础。参数说明client-type这个请求头要放在token校验之前因为同一个账号既可以是发单用户也可以是骑手后端要同时看client-type和user_id去查对应角色表与钱包。顺带说一句UniappX如果你的业务锁定安卓端骑手工具UniappX的渲染性能和原生能力更好但它对iOS和小程序的兼容路径不完全等于Uniapp。跑腿这种需要靠微信小程序获客的项目我会先把业务在Uniapp上跑通不盲目升级到UniappX。2.3 目录设计与数据表拆分订单、骑手、结算、公告的落库思路数据表是这套系统里最不能偷懒的部分。跑腿订单至少需要拆成四类核心表订单主表、订单日志表、骑手表、结算表再加上配置表、公告表、投诉表。业务刚起步时你会觉得表多等跑两个月后再回来看表的拆分价值才会显现。常见核心表如下表名作用核心字段fa_order订单主表order_sn, order_type, status, user_id, rider_id, distance, fee, goods_desfa_order_log状态流转日志order_id, order_status, operator, remarkfa_delivery_user骑手表user_id, id_card, audit_status, balance, total_ordersfa_settlement骑手结算/提现rider_id, order_id, amount, type, statusorder_type字段直接区分帮取pickup和帮送deliver后面加一个帮买purchase也不难。下面是订单主表的建表SQL片段CREATE TABLE fa_order ( id int(11) unsigned NOT NULL AUTO_INCREMENT, order_sn varchar(32) NOT NULL COMMENT 订单号规则见说明, order_type tinyint(1) NOT NULL DEFAULT 1 COMMENT 1帮送 2帮取, status tinyint(1) NOT NULL DEFAULT 0 COMMENT 状态机见3.1, user_id int(11) NOT NULL COMMENT 发单用户, rider_id int(11) DEFAULT 0 COMMENT 接单骑手0未派单, from_address varchar(255) NOT NULL COMMENT 取件地址, to_address varchar(255) DEFAULT COMMENT 送达地址帮送必填, from_lng decimal(10,6) DEFAULT NULL, from_lat decimal(10,6) DEFAULT NULL, to_lng decimal(10,6) DEFAULT NULL, to_lat decimal(10,6) DEFAULT NULL, fee decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT 跑单费, item_desc varchar(255) DEFAULT COMMENT 物品描述, expect_time int(11) DEFAULT 0 COMMENT 期望送达时间戳, created_at int(11) NOT NULL, PRIMARY KEY (id), KEY idx_order_sn (order_sn), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;逻辑说明经纬度直接用decimal(10,6)冗余在订单表里而不是每次去地址表关联是为了骑手端地图刷新时不反复查库。expect_time存的是10位时间戳方便做超时任务。参数说明订单号我一般用“年月日随机数用户尾号”拼成短串避免用自增id对外暴露单量如果以后要异地多仓order_sn里还可以扩展城市码。订单日志表fa_order_log要建复合索引(order_id, created_at)运营后台的订单轨迹页就是按这个查的。结算表不要只记最终金额要记录运费、溢价补贴、赔偿三个明细后台对账时才能说清楚骑手这周为什么少拿了几十块。这个问题后面第5章还会提到。把这张表设计对后面所有统计报表才有的查。3. 帮取与帮送双模式订单状态机、取货码与派单策略怎么落地3.1 从下单到妥投帮送模式的6个状态定义跑腿系统最容易写崩的地方不是接口少而是状态乱。帮送模式的完整链路是用户下单付款 → 骑手接单 → 骑手到取件点取到物品 → 配送到目的地 → 用户确认收货。中间任何一个环节被打断比如骑手取消、用户取消、超时、物品损坏都要有对应状态且不允许乱跳。我把状态码设计成这样状态码含义允许流向0待支付1待接单或 99取消1待接单2已接单或 99取消2已接单/待取件3取件中或 99取消3取件中4配送中或 8异常4配送中5已完成或 8异常5已完成无8异常上报4继续配送或 99取消99已取消无后端这边如果用一堆if else去判断状态后面加需求时很容易漏掉分支。我一般把状态机收敛成一个数组?php // application/api/common.php 状态机定义 const ORDER_STATUS [ pending_payment 0, pending_assign 1, accepted 2, picking 3, delivering 4, completed 5, exception 8, cancelled 99 ]; // 合法流转表当前状态 可跳转目标 const ORDER_FLOW [ 0 [1, 99], // 待支付可去待接单也可取消 1 [2, 99], // 待接单可被骑手接单用户也可取消 2 [3, 99], // 已接单后骑手开始取件 3 [4, 8], // 取到货后配送中或上报异常 4 [5, 8], // 配送中可完成也可能包裹损坏 8 [4, 99], // 异常单可恢复配送也可终止取消 5 [], 99 [] ]; function changeOrderStatus($order, $nextStatus) { $current (int)$order[status]; if (!in_array($nextStatus, ORDER_FLOW[$current], true)) { throw new \Exception(非法状态流转 . $current . - . $nextStatus); } // 更新订单主表状态并追加 fa_order_log 日志 return true; }逻辑说明ORDER_FLOW把“允许做什么”集中在一个数组里所有接口的取消、接单、妥投都调这一个函数就不会出现骑手端把已完成订单改成待接单的尴尬事。参数说明异常状态8是双向门既能继续配送也能取消具体走哪个分支要记录操作人和处理备注。为什么帮送不单独设“骑手到店”状态因为帮送通常是取送一体骑手取到货之后直接进入配送中。帮取就不一样了多了一个和商家核销的环节下面单独说。3.2 帮取模式的特殊边界取货码、拍照凭证与异常上报帮取和帮送的本质区别是帮送做的是A到B的位移帮取是“到店代排队、代买再把商品送回给用户”。中间多了一个面向商家的核销环节。帮取订单在骑手接单后要生成一个取货码商家凭码把商品交给骑手骑手同时拍照留证。取货码的生成逻辑大概是?php // 帮取订单接单时生成6位取货码 public function genPickupCode($orderId) { $order Db::name(order)-find($orderId); if ($order[order_type] ! 2) { $this-error(只有帮取订单需要取货码); } // 生成不重复的6位数字常见做法是随机校验库内唯一 $code random_int(100000, 999999); Db::name(order)-where(id, $orderId)-update([ pickup_code $code, pickup_expire time() 3600 // 一小时内有效 ]); // 骑手端展示给商家商家拍一下留证 return $code; }逻辑说明取货码的过期时间不能设太长太长商家拿着码等人容易扯皮也不宜太短一小时基本够骑手到店。帮取场景里商家一般没有独立客户端所以常见做法是骑手端直接亮码给商家看商家拍照留存后台可按订单号查核销记录。参数说明生成对外凭证用random_int比mt_rand更合适尤其涉及钱和货时别用自增id。帮取代买的异常比帮送多得多缺货要换、需要垫付、排队时间过长。骑手端上报异常时状态走8同时强制填remark和图片运营后台收到异常单要做二次确认确认后退回差额或改价。这个改价动作建议直接生成一条结算调整记录而不是默默改order表里的fee否则月底对账时永远说不清钱去哪了。3.3 派单策略与超时自动取消Redis队列和ThinkPHP命令行任务状态机管住了接口但“谁去接这个单”是运营模式问题。常见做法有三种运营手动指派给指定骑手、骑手在接单大厅抢单、系统按距离和等级自动派单。前两种逻辑简单第三种我一般用Redis队列配合ThinkPHP的队列任务来做。先看一个延迟取消任务的例子?php // application/common.php 下单后15分钟未支付自动取消 use think\Queue; // 下单接口里投递延迟任务 Queue::later(900, function($job) use ($orderId) { $order Db::name(order)-find($orderId); if ($order[status] 0) { // 仍未支付 Db::name(order)-where(id, $orderId)-update([ status 99, cancel_reason 超时未支付自动取消 ]); } $job-delete(); }, orderAutoCancel);逻辑说明Queue::later第一个参数是延迟秒数这里是900秒15分钟回调里先查一次当前状态只有仍然待支付才允许自动取消。为什么不能只靠前端倒计时因为用户可能关掉页面App进程被杀后端定时任务才算兜底。参数说明ThinkPHP的队列需要单独跑消费命令比如php think queue:listen部署时别忘了在进程守护里拉起它否则延迟任务不会执行。自动派单也可以用Redis队列订单进入待接单状态时把订单id推入列表骑手端请求附近可抢单接口时从这个池里取单。不过要留意“先到先得”还是“权重优先”抢单请求高并发下容易出现两个骑手同时抢同一单判重逻辑要放在数据库行锁里。我常用的参数是初始派单半径3公里每5分钟扩大1公里最大扩到8公里超时未接单回退给运营手动指派。这套参数在城区和县城差别很大别指望一套通用上线后按城市密度调。4. Uniapp客户端落地定位跟踪、消息推送与微信小程序打包4.1 前后台持续定位plus.geolocation.watchPosition与uni.startLocation的配合骑手端最敏感的功能是定位。用户要看骑手到哪了骑手后台要记录轨迹核对实际里程。但Uniapp自带的uni.startLocation在App切到后台后会被系统省电策略暂停iOS对后台定位管得更严。常见的双保险做法是前台用plus.geolocation.watchPosition持续监听同时用uni.startLocation做兜底切后台时开启后台定位监听并在manifest里声明对应权限。manifest.json里需要配置两块内容App模块权限里声明地理位置iOS的UIBackgroundModes里加location{ app-plus: { usingComponents: true, distribute: { ios: { UIBackgroundModes: [location] }, android: { permissions: [ ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION, ACCESS_BACKGROUND_LOCATION, FOREGROUND_SERVICE ] } }, modules: { Geolocation: {}, Messaging: {} } } }逻辑说明Android端要做后台持续定位单有权限声明还不够国内厂商ROM的省电策略会把App杀掉需要在代码里拉起前台服务并引导用户把App加入电池白名单。iOS端必须在UIBackgroundModes里声明location否则切后台几分钟定位全部停掉。参数说明ACCESS_BACKGROUND_LOCATION是Android 10以后的后台定位权限需要用户单独在系统设置里授权一次这个授权入口很多用户找不到App里要写清楚引导话术。代码层的定位监听我一般这样处理// 骑手端地图页持续采集位置并节流上报 export function startTrack() { uni.startLocation({ type: gcj02, accuracy: Nearest, success: () { // 前台监听间隔可以调短 plus.geolocation.watchPosition( (pos) { const coords pos.coords; // 节流10秒上报一次避免接口被刷 uploadPosition(coords.longitude, coords.latitude); }, (err) console.error(watchPosition失败, err), { enableHighAccuracy: true, maximumAge: 5000, timeout: 10000 } ); }, fail: (err) { // startLocation失败时降级成单次定位 plus.geolocation.getCurrentPosition(uploadPosition, () {}); } }); }逻辑说明watchPosition是App端的原生持续定位返回坐标系是gcj02正好适合拼到高德或腾讯地图上。uploadPosition内部做时间节流10秒一次既保持轨迹连续性又不至于把ThinkPHP接口打爆。startLocation的fail回调不要静默至少打日志否则定位模块出问题就像黑匣子一样难查。4.2 订单状态变化通知Uniapp拦截器与WebSocket消息推送用户端和骑手端都希望状态“实时”变化骑手接单了、开始取件了、已到达。最简单是轮询但同城跑腿单量上去后轮询很费服务器。常见做法是即时消息走WebSocket关键状态再补一次站内通知兜底。无论是轮询还是推送请求封装是第一步// common/request.js 统一请求封装 const request (url, data {}, method POST) { return new Promise((resolve, reject) { uni.request({ url: BASE_URL url, method, data, header: { X-Token: uni.getStorageSync(token), Content-Type: application/json }, success: (res) { // 后台返回code0是成功401是登录失效 if (res.data.code 0) { resolve(res.data.data); } else if (res.data.code 401) { uni.navigateTo({ url: /pages/login/index }); reject(res.data); } else { uni.showToast({ title: res.data.msg, icon: none }); reject(res.data); } }, fail: (err) reject(err) }); }); }; // 骑手端抢单接口 export const acceptOrder (orderId) request(/api/order/accept, { order_id: orderId });逻辑说明token统一放在请求头里后端Base控制器统一校验401统一踢回登录页。这个封装同时服务于用户端和骑手端后续加版本号、加埋点都只改这一处。参数说明BASE_URL要区分开发和生产环境真机调试时换成局域网IP或线上域名否则会莫名请求失败。状态推送我倾向用WebSocket用户在订单详情页时监听订单状态事件骑手端全局监听新订单事件。后端用ThinkPHP的Workerman插件跑长连接客户端要做好断线重连重连后把当前页面能取到的订单id重新订阅一遍避免漏消息。小程序端不支持长连接时退回到订阅消息但订阅消息有次数限制所以重要的状态如“骑手已接单”“订单已取消”各发一次就好别给用户堆消息容易招投诉。4.3 微信小程序打包的2MB限制与manifest配置分包与隐私配置小程序端的坑最直接微信开发者工具编着编着就报source size 2612kb exceed max limit 2mb。出现这个不用慌主包超限九成是因为把Uniapp基础组件和easycom组件全编译进去了。解决思路就两招主包瘦身、业务分包。主包只保留tabBar页面和公共请求库订单详情、结算页、帮助中心全部踢到分包里。pages.json配置{ pages: [ { path: pages/index/index, style: { navigationBarTitleText: 首页 } }, { path: pages/order/list, style: { navigationBarTitleText: 我的订单 } } ], subPackages: [ { root: packageOrder, pages: [ { path: detail, style: { navigationBarTitleText: 订单详情 } }, { path: confirm, style: { navigationBarTitleText: 确认下单 } }, { path: comment, style: { navigationBarTitleText: 评价 } } ] }, { root: packageRider, pages: [ { path: accept, style: { navigationBarTitleText: 抢单大厅 } }, { path: deliver, style: { navigationBarTitleText: 配送中 } } ] } ], preloadRule: { pages/order/list: { network: all, packages: [packageOrder] } } }逻辑说明subPackages按业务域拆分用户端打包时只带packageOrder骑手端打包时带上packageRider公共页面留在主包。preloadRule让用户进入订单列表时预下载分包平衡首屏体积和体验。参数说明tabBar页面必须留在主包pages里放进subPackages会直接编译失败这是微信的硬性规定。与打包配套的manifest.json里小程序appid填自己的权限勾选位置信息、相册、摄像头这是取货码拍照和地图定位要用的。自定义分享好友的场景通常是用户邀请有礼onShareAppMessage返回title和path把邀请人的user_id带在query里后端就能统计邀请关系。另外还有一类隐藏体积静态图片不要打包进小程序全部走后台附件域名或CDN否则几张运营banner就能吃满配额。等分包也撑不住时就需要排查easycom组件依赖把只在骑手端用的地图组件改成按需import这一步在常见问题里再细说。5. 上线避坑清单Fastadmin上传漏洞、定位权限与打包翻车的高频排查5.1 Fastadmin上传文件漏洞检测路径与修补方法Fastadmin上传文件漏洞是运维圈的老面孔了。后台附件管理允许上传文件如果再把public/uploads放在web根目录且未限制脚本执行攻击者传一个php上去就等于拿到了webshell。我接手这类跑腿系统时第一件事是扫public/uploads目录下有没有可疑的php文件再检查附件配置。应急做法是在nginx里禁止uploads目录解析PHP# nginx 站点配置里加一段放在 server 块内 location ~* /uploads/.*\.(php|php5|phtml|asp|aspx|jsp)$ { deny all; return 403; } # 可选uploads目录彻底不解析PHP location /uploads/ { if ($request_uri ~ \.php$) { return 403; } }逻辑说明把uploads目录下的PHP解析直接禁掉即使攻击者上传了恶意文件也执行不了这是成本最低的止血方式。同时要把Fastadmin后台的上传校验收紧附件扩展名白名单只留jpg/png/gif/mp4/pdf并限制单个文件大小。参数说明如果你用的是宝塔面板在站点配置里找到NGINX配置或伪静态把上面location段加进去保存后重载即可。除了上传目录还要检查生产环境的APP_DEBUG必须为false。我见过有外包项目开发调试模式不关直接上线异常信息把服务器路径和数据库结构全暴露了这比上传漏洞更基础。还有Fastadmin后台默认弱口令admin/123456这类上线前务必强制改掉并把登录验证码打开。5.2 后台定位失效manifest后台运行权限与iOS系统限制现象骑手把App切到后台订单详情页里骑手位置一直停在原地过一会儿彻底不更新了。原因分两种Android端被系统省电策略杀了进程iOS端后台定位权限没声明或用户没授权。解决办法在4.1已经写了配置这里补两个代码之外的关键点。第一Android端即使加了FOREGROUND_SERVICE权限也要在实际代码里启动一个通知栏前台服务否则部分ROM几小时后仍会回收进程。常见做法是骑手开始接单时启动前台服务通知栏显示“优创跑腿正在后台定位”并引导用户进入系统电池白名单。注意引导文案不要写“永不掉线”这类承诺正确说法是“关闭省电策略以获得更准确的定位”。这地方各厂商ROM行为不一样本身就是玄学只能做到让大多数机型可用。第二iOS端要在首次打开App时就弹定位权限说明说明不能只写“用于定位”而要写具体用途比如“用于骑手配送轨迹记录与订单位置展示”。iOS审核对后台定位用途说明很敏感用途讲不清楚会被拒。plus.geolocation.watchPosition在iOS后台不会持续回调配合uni.startLocation也只能保持一定频率所以后台定位精度期望要合理轨迹有缺口时用两点间连线补上即可。5.3 小程序包体积超限source size 2612kb的拆包方案现象微信开发者工具编译报source size 2612kb exceed max limit 2mb点击预览或真机调试都失败。原因主包把所有页面和组件一起编译Uniapp基础组件库本身就占用不少空间再加上地图库、图表库一起进来就容易超。解决步骤在pages.json里把所有非tabBar页面迁到subPackages主包只留首页和我的。静态图片全部替换成CDN地址本地只留图标文件运营banner不要打包。到HBuilderX的uni_modules里关掉没用到的插件有些插件会连带把依赖组件编进主包。重新打包后用微信开发者工具的包分析页看主包占比再针对大户拆。如果做完这些仍然超限大概率是pages.json里有几条页面漏迁移还留在主包pages数组里。另一个隐蔽点是easycom组件会被自动注册到主包骑手端专用的地图弹窗组件不要放在公共components目录放到分包目录里按需import。改动之后记得清一次HBuilderX的缓存再编译有时候工具不刷新。5.4 uniapp真机调试不打印日志排查与解决办法现象HBuilderX里点真机运行App能打开但console.log全都没有输出。原因Android真机没开启USB调试、HBuilderX版本与手机不匹配、或者当前运行的是旧基座而不是自定义基座。排查路径确认开发者选项里的USB调试已打开数据线插的是有数据通道的口不是充电口。看HBuilderX的运行菜单是否显示“运行到手机App基座”如果用的是老基座需要重新制作自定义基座。代码里临时改用uni.showToast打印关键信息或者用plus.console.log输出到原生日志再用adb logcat抓取。这里有个血泪经验真机日志不输出时先别改代码先查基座和USB连接折腾半天改代码是浪费时间。如果自定义基座构建时勾选模块太多或与工程不一致也会导致基座异常重装一次基座再试。联调状态机接口时让后端把ThinkPHP的日志级别开到debug两边日志对着看很多问题都是接口返回了但前端没解析对。5.5 热更新与上架审核的取舍什么时候该用热更新Uniapp的App端热更新只能更新js资源也就是wgt包原生SDK、权限声明、manifest配置改了都必须重新打包上架。跑腿系统里最容易踩的坑就是拿热更新去顶原生模块改动比如新增一个平台的支付SDK或者改了iOS后台定位权限这类改动用wgt包根本救不了用户端表现为“明明更新了版本但新功能没出现”。我一般定这样一个策略可以走热更新页面排版、活动配置、接口地址切换、状态文案调整。必须重新打包上架新增原生插件、修改manifest权限、升级支付或地图SDK、iOS后台定位声明变更。上线前把热更新版本号和原生版本号分开校验客户端先比对本地的原生版本再检测热更新包的版本避免wgt包指向一个坏的版本把用户带崩。安卓应用市场上架时很多商店要求提交隐私政策说明热更新包内容也在合规范围内不要在wgt里塞未审查的功能否则不是驳回一次的问题是被下架。热更新虽方便也有它的边界跑腿系统里最稳妥的还是把它当“配置下发”用不碰原生能力。6. 把系统推到生产部署验证与多端维护的几个实用习惯部署顺序我习惯落后台再落接口最后接客户端。ThinkPHP项目运行前先把runtime目录权限给到www用户新增控制器或修改composer autoload后要执行php think clear再调接口否则会莫名加载旧代码。nginx伪静态要把请求转发到index.php同时排除public/uploads目录改完配置记得nginx -t再reload。上线前的验证别省这几步全流程状态机走一遍下单-支付-派单-接单-取件-妥投再走一遍异常单骑手上报-后台处理-恢复配送或取消。然后核对结算表运费、优惠、赔款三列加起来要等于骑手实际入账最容易账不平的是帮买垫付金额没单独记录。还有个小习惯每次发版前用同一个账号在测试环境整单跑一遍别只看登录和列表页。多端维护的另一个实用技巧是API接口带版本。用户端、骑手端、小程序发布节奏不同后端加字段不要直接改老接口路径里带v1、v2老版本保三个月。我吃过大亏有一次为了赶需求改了原接口返回结构没带版本还在审核中的小程序调用老接口解析不到数据运营直接炸了。从那以后任何字段变更都先看客户端版本版本不一致宁可新开一个接口。给准备上手这个项目方向的同行一个建议先不折腾自动派单手动指派加抢单模式先跑起来订单量上来后再上Redis队列自动派单。把状态机、日志表、结算表这三个底座做好后续改价、多城市运营都只是往底座上添页面。希望这些踩坑记录能帮你少走一段弯路。本文还有配套的精品资源点击获取
返回列表