华鲜生项目 — 现成系统源代码改动清单
基于 美国项目-BULK FOOD系统源代码(ThinkPHP 6 + uni-app + Vue.js)源码深度分析
分析日期:2026-08-14
系统现状总结
经过对原始代码的全量扫描,发现系统已经内置了大量核心能力,实际需要的改动量远小于从零开发。以下是已有能力清单:
| 模块 | 已有能力 | 状态 |
|---|---|---|
| 支付系统 | 微信支付 V2/V3、支付宝、通联支付、Stripe | ✅ 已有驱动 |
| WMS 仓储 | 智能分仓 allocateOrder、出库单生成、温控分类、库存管理 |
✅ 已有完整模块 |
| 司机配送端APP | 独立 Driver 应用、接单/在途/签收状态机、GPS 上报、拍照签收 | ✅ 已有独立应用 |
| Google Maps | 配送距离计算 calculateDistance、路线导航链接生成 |
✅ 已集成 |
| 快递物流 | 轨迹查询、电子面单打印、快递员上门寄件 | ✅ 已有驱动 |
| 订单系统 | 创建/拆单/发货/退款/核销/自动收货、4种发货模式 | ✅ 完整闭环 |
| 客服系统 | 独立客服应用、实时聊天、客服话术、工单转接 | ✅ 已有独立应用 |
核心改动集中在两个方向:① PIX 支付驱动新增 和 ② 第三方同城配送平台 API 对接。微信海外支付仅需配置调整,无需新增代码。
一、PIX 支付对接(巴西本地支付)
优先级:🔴 P0 — 上线必备
PIX 是巴西央行推出的即时支付系统,覆盖率超 95%,是华鲜生在巴西运营的第一支付方式。
1.1 技术选型建议
| 网关服务商 | 优势 | 推荐度 |
|---|---|---|
| MercadoPago | 巴西最大支付平台,PIX/信用卡/Boleto 全覆盖,SDK 成熟 | ⭐⭐⭐⭐⭐ |
| Ebanx | 拉美跨境支付专家,支持中国企业主体 | ⭐⭐⭐⭐ |
| PagSeguro | 巴西本土老牌,生态完善 | ⭐⭐⭐ |
推荐 MercadoPago,其提供完整的 PIX 即时支付 API(生成 BR Code + Copia e Cola),且有 Webhook 自动回调机制,与 CRMEB 的 Manager-Driver 模式完美兼容。
1.2 后端 — 新增 PIX 支付驱动(crmeb 核心层)
[NEW] crmeb/services/pay/storage/PixPay.php
PIX 支付驱动,实现
PayInterface接口,与微信/支付宝/Stripe 驱动平级。
需实现的接口方法:
├── create() → 调用 MercadoPago API 创建 PIX 收款请求
│ 返回:PIX QR Code (Base64 图片)、BR Code 字符串、
│ Copia e Cola 文本、过期时间
├── handleNotify() → 接收 MercadoPago Webhook(IPN)回调
│ 验证签名 → 解析支付状态 → 触发 NotifyListener 事件
├── refund() → 调用 MercadoPago 退款 API(PIX 原路退回)
├── queryRefund() → 查询退款状态
└── merchantPay() → 商家 PIX 转账(用于佣金提现到供应商/配送员 PIX 账户)
关键实现细节:
- PIX 收款请求有效期设为 30 分钟(生鲜订单时效性要求)
- Webhook 签名验证使用 MercadoPago 提供的
x-signatureheader 与 HMAC-SHA256 - 支付成功后,通过
Event::until('NotifyListener', [$data, 'pix'])派发给业务层
[NEW] crmeb/services/pay/extend/mercadopago/MercadoPagoClient.php
MercadoPago API HTTP 客户端封装(类似已有的
allinpay/Client.php)
封装方法:
├── createPixPayment($amount, $description, $externalRef, $expiration)
├── getPaymentStatus($paymentId)
├── refundPayment($paymentId, $amount)
├── validateWebhookSignature($headers, $body)
└── createPixTransfer($pixKey, $amount, $description)
[MODIFY] crmeb/services/pay/Pay.php
在支付管理器中注册 PIX 驱动
protected function getSpace(): string
{
return '\\crmeb\\services\\pay\\storage\\';
}
+ // 在驱动名映射中增加 PIX
+ // 确保 driver('pix') 能正确实例化 PixPay 类
改动量:约 3-5 行
[MODIFY] crmeb/services/pay/BasePay.php
在基类中添加 PIX 渠道的终端类型判断逻辑
+ case 'pix':
+ // PIX 不区分终端,统一返回 QR Code
+ break;
改动量:约 5-8 行
1.3 后端 — 业务层适配(app 层)
[MODIFY] app/services/pay/PayServices.php
在统一支付服务中添加 PIX 支付常量与分支
const WEIXIN_PAY = 'weixin';
const ALIAPY_PAY = 'alipay';
const ALLIN_PAY = 'allinpay';
const STRIPE = 'stripe';
+ const PIX_PAY = 'pix';
// 在 pay() 方法中增加 PIX 分支
+ case self::PIX_PAY:
+ $payInfo = app()->make(\crmeb\services\pay\Pay::class)
+ ->driver('pix')
+ ->create($orderId, $totalFee, $attach, $body, $detail);
+ // 返回 QR Code 和 Copia e Cola 给前端
+ break;
改动量:约 15-20 行
[MODIFY] app/services/pay/OrderPayServices.php
在订单支付前置处理中添加 PIX 渠道的参数装配
+ case PayServices::PIX_PAY:
+ $payInfo['pix_qr_code'] = $result['qr_code'];
+ $payInfo['pix_qr_code_base64'] = $result['qr_code_base64'];
+ $payInfo['pix_copia_cola'] = $result['copia_cola'];
+ $payInfo['pix_expiration'] = $result['expiration'];
+ break;
改动量:约 10-15 行
[MODIFY] app/services/pay/PayNotifyServices.php
在支付回调分发中增加 PIX 回调处理逻辑
+ case 'pix':
+ // 从 MercadoPago Webhook 数据中提取商户订单号
+ $orderSn = $data['external_reference'];
+ $this->paySuccess($orderSn);
+ break;
改动量:约 8-12 行
[NEW] app/api/controller/v1/pay/PixNotifyController.php
PIX 支付 Webhook 回调入口控制器
功能:
├── notify() → 接收 MercadoPago IPN 通知
│ 验证签名 → 调用 PayNotifyServices 处理
└── 路由注册 → POST /api/pay/notify/pix
1.4 路由注册
[MODIFY] app/api/route/v1.php
新增 PIX 回调路由(无需授权中间件)
+ // PIX 支付异步回调(MercadoPago Webhook)
+ Route::post('pay/notify/pix', 'v1.pay.PixNotifyController/notify')
+ ->option(['real_name' => 'PIX支付异步回调']);
改动量:约 3 行
1.5 配置文件
[MODIFY] config/pay.php
在支付方式与驱动列表中注册 PIX
'payType' => [
'weixin' => '微信支付',
'yue' => '余额支付',
'offline' => '线下支付',
+ 'pix' => 'PIX即时支付',
],
'stores' => [
'wechat_pay' => [],
'ali_pay' => [],
'yue' => [],
+ 'pix' => [
+ 'access_token' => '', // MercadoPago Access Token
+ 'public_key' => '', // MercadoPago Public Key
+ 'webhook_secret' => '', // Webhook 签名密钥
+ ],
]
改动量:约 10 行
1.6 前端改动(用户端 H5 / 小程序)
前端代码当前为编译后的产物(public/static/、public/statics/mp_view/),修改需要获取 uni-app 原始源码工程后重新编译。如果没有源码,则需要在编译后的 JS 中定位并修改(难度较高但可行)。
[MODIFY] 收银台/支付选择页面
改动内容:
├── 增加「PIX 即时支付」选项按钮(带 PIX 图标)
├── 选择 PIX 后,调用统一下单接口传入 payType='pix'
├── 支付接口返回后,展示:
│ ├── PIX QR Code 二维码图片(供扫码支付)
│ ├── "Copiar Código" 一键复制按钮(复制 Copia e Cola 代码)
│ └── 倒计时器(30分钟过期提醒)
└── 前端轮询订单状态(每 3 秒一次),支付成功后跳转成功页
[MODIFY] 订单详情页 — 支付方式显示
增加 PIX 支付方式的图标与文字标识
1.7 管理后台改动
[MODIFY] 后台 — 系统设置 / 支付配置页面
改动内容:
├── 新增「PIX 支付配置」表单分组
│ ├── MercadoPago Access Token(输入框)
│ ├── MercadoPago Public Key(输入框)
│ ├── Webhook Secret(输入框)
│ └── Webhook URL 展示(只读,供商户复制到 MercadoPago 后台配置)
└── 新增「PIX 开关」(是否启用 PIX 支付)
二、微信支付海外版适配
优先级:🟡 P1 — 重要但非紧急
使用海外企业主体申请的微信支付商户号,接入方式与国内微信支付略有差异。
系统已内置完整的微信支付 V3 驱动(crmeb/services/pay/storage/V3WechatPay.php),且已支持服务商模式(ISV)参数(sp_appid, sp_mchid, sub_mchid)。海外微信支付的核心差异仅在于货币单位和API 域名,无需新增驱动。
2.1 后端改动
[MODIFY] crmeb/services/pay/storage/V3WechatPay.php
// 1. API 域名适配:海外商户需使用 hk.api.weixin.qq.com
+ private function getApiHost(): string
+ {
+ $isOverseas = sys_config('wechat_pay_overseas', 0);
+ return $isOverseas ? 'https://apihk.mch.weixin.qq.com' : 'https://api.mch.weixin.qq.com';
+ }
// 2. 货币代码:海外商户使用 BRL(巴西雷亚尔)
+ // 在 create() 方法的请求体中:
+ 'amount' => [
+ 'total' => intval(bcmul($totalFee, 100)),
- 'currency' => 'CNY',
+ 'currency' => sys_config('wechat_pay_currency', 'CNY'),
+ ],
改动量:约 15-20 行
[MODIFY] crmeb/services/easywechat/v3pay/PayClient.php
调整 V3 支付请求的基础 URL 为可配置
- const BASE_URI = 'https://api.mch.weixin.qq.com';
+ protected $baseUri;
+
+ public function __construct($config)
+ {
+ $this->baseUri = $config['overseas'] ? 'https://apihk.mch.weixin.qq.com' : 'https://api.mch.weixin.qq.com';
+ }
改动量:约 5-8 行
2.2 配置改动
[MODIFY] 后台 — 微信支付配置页面
新增配置项:
├── 「是否海外商户」开关(wechat_pay_overseas: 0/1)
├── 「结算货币」下拉选择(wechat_pay_currency: CNY/BRL/USD/...)
└── 「API 域名模式」(自动根据海外开关切换,无需手动填写)
海外微信支付的小程序 AppID 和商户号与国内格式完全相同,现有后台的 AppID / MchID / APIv3 密钥 / 证书上传功能无需任何改动,直接填入海外商户信息即可。
三、第三方同城配送平台对接(Lalamove / Loggi / UBER)
优先级:🔴 P0 — 上线必备
实现后台一键询价、一键呼叫骑手、轨迹回传、自动变更订单状态。
3.1 技术架构设计
采用与现有支付/物流相同的 Manager-Driver 模式,新增「同城配送」服务管理器,使 Lalamove 和 Loggi 可作为可插拔驱动热切换。
crmeb/services/citydelivery/ ← 新增目录
├── BaseCityDelivery.php ← 抽象基类
├── CityDelivery.php ← 驱动管理器 (extends BaseManager)
├── CityDeliveryInterface.php ← 统一接口规范
└── storage/
├── Lalamove.php ← Lalamove 驱动实现
└── Loggi.php ← Loggi 驱动实现(可后续扩展)
3.2 后端 — 新增同城配送服务( 核心层)
[NEW] crmeb/services/citydelivery/CityDeliveryInterface.php
统一接口规范,所有同城配送驱动必须实现
interface CityDeliveryInterface
{
/**
* 询价 — 获取运费报价
* @param array $origin 发货地 ['lat' => '', 'lng' => '', 'address' => '']
* @param array $destination 收货地 ['lat' => '', 'lng' => '', 'address' => '']
* @param array $options 附加参数 ['weight' => 0, 'vehicle' => 'MOTORCYCLE']
* @return array ['price' => 15.00, 'currency' => 'BRL', 'estimated_time' => '35min', 'vehicle_type' => 'MOTORCYCLE']
*/
public function getQuotation(array $origin, array $destination, array $options = []): array;
/**
* 下单呼叫 — 创建配送订单
* @param string $quotationId 询价返回的报价 ID
* @param array $sender 发件人信息
* @param array $recipient 收件人信息
* @param array $items 物品描述
* @return array ['order_id' => '', 'tracking_url' => '', 'driver_info' => []]
*/
public function createOrder(string $quotationId, array $sender, array $recipient, array $items = []): array;
/**
* 取消配送订单
*/
public function cancelOrder(string $orderId): bool;
/**
* 获取配送订单详情(含骑手信息与实时位置)
*/
public function getOrderDetail(string $orderId): array;
/**
* 获取支持的车辆类型列表
*/
public function getVehicleTypes(): array;
/**
* 验证 Webhook 回调签名
*/
public function validateWebhook(array $headers, string $body): array;
}
[NEW] crmeb/services/citydelivery/BaseCityDelivery.php
抽象基类,封装公共逻辑(继承
BaseStorage)
封装内容:
├── initialize() → 从 sys_config 读取 API Key / Secret
├── getOrigin() → 获取仓库/发货点经纬度(从 WMS 仓库配置中读取)
├── formatAddress() → 地址格式标准化(巴西地址格式:Rua/Av + Número + Bairro + CEP)
└── logDeliveryRequest() → 记录每次 API 调用的请求与响应日志
[NEW] crmeb/services/citydelivery/CityDelivery.php
驱动管理器(继承
BaseManager),支持driver('lalamove')/driver('loggi')动态切换
class CityDelivery extends BaseManager
{
protected $namespace = '\\crmeb\\services\\citydelivery\\storage\\';
protected function getSpace(): string
{
return $this->namespace;
}
// 默认驱动从后台配置读取
protected function getDefaultDriver(): string
{
return sys_config('city_delivery_driver', 'lalamove');
}
}
[NEW] crmeb/services/citydelivery/storage/Lalamove.php
Lalamove API 驱动实现(implements
CityDeliveryInterface)
核心实现:
├── getQuotation()
│ ├── POST https://rest.lalamove.com/v3/quotations
│ ├── Header: Authorization (HMAC-SHA256 签名)
│ ├── Body: { serviceType, language, stops[], item{} }
│ └── 返回: priceBreakdown, expiresAt, quotationId
│
├── createOrder()
│ ├── POST https://rest.lalamove.com/v3/orders
│ ├── Body: { quotationId, sender{}, recipients[], metadata{} }
│ │ metadata.externalOrderId = 华鲜生内部订单号(用于回调关联)
│ └── 返回: orderId, shareLink(客户追踪链接)
│
├── cancelOrder()
│ ├── DELETE https://rest.lalamove.com/v3/orders/{orderId}
│ └── 仅在骑手接单前可取消
│
├── getOrderDetail()
│ ├── GET https://rest.lalamove.com/v3/orders/{orderId}
│ └── 返回: status, driverInfo{name, phone, plateNumber}, shareLink
│
├── getVehicleTypes()
│ └── 巴西支持: MOTORCYCLE (摩托车), CAR (轿车), VAN (面包车), TRUCK (货车)
│
├── validateWebhook()
│ ├── 验证 X-Lalamove-Signature header
│ └── 解析状态: ASSIGNING_DRIVER → DRIVER_FOUND → PICKED_UP → COMPLETED
│
└── _generateSignature() (私有方法)
├── 构造签名字符串: {timestamp}\r\n{method}\r\n{path}\r\n\r\n{body}
└── HMAC-SHA256 加密,格式: hmac {apiKey}:{timestamp}:{signature}
Lalamove 巴西 API 的 Base URL 为 https://rest.lalamove.com(正式环境),测试沙箱为 https://rest.sandbox.lalamove.com。市场代码使用 BR_SP(巴西圣保罗)。
[NEW] crmeb/services/citydelivery/storage/Loggi.php
Loggi 配送 API 驱动实现(后续扩展,初期可为空壳)
Loggi 使用 GraphQL API,接口风格与 Lalamove REST 不同:
├── getQuotation() → mutation { createOrder(input: ...) }
├── createOrder() → 同上(Loggi 的询价和下单合并在一个 mutation 中)
├── cancelOrder() → mutation { cancelOrder(pk: ...) }
└── getOrderDetail() → query { orderByPk(pk: ...) }
3.3 后端 — 业务层集成(app 层)
[NEW] app/services/wms/CityDeliveryServices.php
同城配送业务服务类 — 连接 WMS 出库单与第三方配送平台
核心方法:
├── getQuotation($wastageId)
│ ├── 从出库单(Wastage)中读取收货地址经纬度
│ ├── 从仓库配置中读取发货地址经纬度
│ ├── 根据出库单温控属性选择车辆类型:
│ │ ├── delivery_temp=0 (常温) + 重量<15kg → MOTORCYCLE
│ │ ├── delivery_temp=1 (冷藏) → VAN(需要保温箱空间)
│ │ └── 重量>30kg 或 B端大单 → TRUCK
│ └── 调用 CityDelivery::driver()->getQuotation()
│
├── createDeliveryOrder($wastageId, $quotationId)
│ ├── 调用 CityDelivery::driver()->createOrder()
│ ├── 将返回的第三方订单号、骑手追踪链接存入出库单
│ ├── 更新出库单状态:30 (待取货/已派单)
│ └── 更新商城订单状态为「已发货」+ 物流信息
│
├── handleWebhook($data)
│ ├── DRIVER_FOUND → 更新骑手姓名、电话、车牌号到出库单
│ ├── PICKED_UP → 出库单状态改为 40 (配送中)
│ ├── COMPLETED → 出库单状态改为 60 (已签收)
│ │ → 商城订单状态改为「已收货」
│ └── REJECTED/EXPIRED → 标记配送异常,通知客服重新派单
│
├── cancelDelivery($wastageId)
│ ├── 调用 CityDelivery::driver()->cancelOrder()
│ └── 出库单状态回退为 20 (待出库/已拣货)
│
└── getDeliveryTracking($wastageId)
└── 返回第三方追踪链接 (shareLink) 给前端展示
[MODIFY] app/services/wms/WmsWastageServices.php
在现有出库/配送流转服务中集成第三方配送选项
// 现有的 delivery() 方法(选择配送方式)中新增分支:
+ case 'city_delivery':
+ // 第三方同城配送
+ $cityDeliveryService = app()->make(CityDeliveryServices::class);
+ $result = $cityDeliveryService->createDeliveryOrder($wastageId, $data['quotation_id']);
+ break;
// 现有状态机中新增「第三方配送」相关状态标识
+ // delivery_type 字段新增值:3 = 第三方同城配送(区别于 1=快递, 2=自建司机配送)
改动量:约 20-30 行
[MODIFY] app/services/order/StoreOrderDeliveryServices.php
在订单发货服务中打通第三方同城配送渠道
// 现有发货模式:1=快递发货, 2=配送员送货, 3=虚拟发货, 4=WMS仓储派单
+ // 新增 type=5:第三方同城配送(Lalamove/Loggi)
+ case 5:
+ // 通过 CityDeliveryServices 呼叫第三方骑手
+ $deliveryInfo = $cityDeliveryService->createDeliveryOrder(...);
+ // 将追踪链接写入订单的物流信息
+ $this->update($orderId, [
+ 'delivery_type' => 'city_delivery',
+ 'delivery_id' => $deliveryInfo['order_id'],
+ 'delivery_tracking_url' => $deliveryInfo['tracking_url'],
+ ]);
+ break;
改动量:约 25-35 行
3.4 路由注册
[MODIFY] app/adminapi/route/wms.php
在 WMS 路由组中新增同城配送相关接口
+ // 第三方同城配送
+ Route::get('delivery/quotation/:wastage_id', 'v1.wms.Wastage/getQuotation')
+ ->option(['real_name' => '获取第三方配送报价']);
+ Route::post('delivery/create', 'v1.wms.Wastage/createCityDelivery')
+ ->option(['real_name' => '呼叫第三方骑手']);
+ Route::post('delivery/cancel/:wastage_id', 'v1.wms.Wastage/cancelCityDelivery')
+ ->option(['real_name' => '取消第三方配送']);
+ Route::get('delivery/tracking/:wastage_id', 'v1.wms.Wastage/getDeliveryTracking')
+ ->option(['real_name' => '获取配送追踪']);
+ Route::get('delivery/vehicle_types', 'v1.wms.Wastage/getVehicleTypes')
+ ->option(['real_name' => '获取支持车辆类型']);
改动量:约 12 行
[MODIFY] app/api/route/v1.php
新增第三方配送 Webhook 回调路由(无需授权)
+ // 第三方同城配送回调
+ Route::post('delivery/notify/lalamove', 'v1.pay.CityDeliveryNotifyController/lalamoveNotify')
+ ->option(['real_name' => 'Lalamove配送状态回调']);
+ Route::post('delivery/notify/loggi', 'v1.pay.CityDeliveryNotifyController/loggiNotify')
+ ->option(['real_name' => 'Loggi配送状态回调']);
改动量:约 6 行
3.5 后台控制器
[MODIFY] app/adminapi/controller/v1/wms/Wastage.php
在现有出库控制器中新增同城配送操作方法
+ /**
+ * 获取第三方配送报价
+ */
+ public function getQuotation($wastage_id)
+ {
+ $data = $this->services->getCityDeliveryQuotation($wastage_id);
+ return app('json')->success($data);
+ }
+ /**
+ * 呼叫第三方骑手
+ */
+ public function createCityDelivery()
+ {
+ $data = $this->request->postMore([
+ ['wastage_id', 0],
+ ['quotation_id', ''],
+ ['vehicle_type', 'MOTORCYCLE'],
+ ]);
+ $result = $this->services->createCityDeliveryOrder($data);
+ return app('json')->success('已成功呼叫骑手', $result);
+ }
+ /**
+ * 取消第三方配送
+ */
+ public function cancelCityDelivery($wastage_id) { ... }
+ /**
+ * 获取配送追踪链接
+ */
+ public function getDeliveryTracking($wastage_id) { ... }
改动量:约 50-60 行
[NEW] app/api/controller/v1/pay/CityDeliveryNotifyController.php
第三方配送平台 Webhook 回调入口
方法:
├── lalamoveNotify() → 接收 Lalamove 状态推送
│ 验签 → 调用 CityDeliveryServices::handleWebhook()
└── loggiNotify() → 接收 Loggi 状态推送
3.6 数据库改动
[MODIFY] WMS 出库单表 (eb_wms_document 或对应出库单表)
新增字段以存储第三方配送信息
ALTER TABLE `eb_wms_document` ADD COLUMN `city_delivery_type` TINYINT(1) DEFAULT 0 COMMENT '同城配送类型: 0=无, 1=Lalamove, 2=Loggi' AFTER `delivery_temp`;
ALTER TABLE `eb_wms_document` ADD COLUMN `city_delivery_order_id` VARCHAR(100) DEFAULT '' COMMENT '第三方配送订单号' AFTER `city_delivery_type`;
ALTER TABLE `eb_wms_document` ADD COLUMN `city_delivery_tracking_url` VARCHAR(500) DEFAULT '' COMMENT '配送追踪链接' AFTER `city_delivery_order_id`;
ALTER TABLE `eb_wms_document` ADD COLUMN `city_delivery_driver_name` VARCHAR(50) DEFAULT '' COMMENT '骑手姓名' AFTER `city_delivery_tracking_url`;
ALTER TABLE `eb_wms_document` ADD COLUMN `city_delivery_driver_phone` VARCHAR(20) DEFAULT '' COMMENT '骑手电话' AFTER `city_delivery_driver_name`;
ALTER TABLE `eb_wms_document` ADD COLUMN `city_delivery_driver_plate` VARCHAR(20) DEFAULT '' COMMENT '骑手车牌号' AFTER `city_delivery_driver_phone`;
ALTER TABLE `eb_wms_document` ADD COLUMN `city_delivery_price` DECIMAL(8,2) DEFAULT 0.00 COMMENT '第三方配送费用(BRL)' AFTER `city_delivery_driver_plate`;
ALTER TABLE `eb_wms_document` ADD COLUMN `city_delivery_status` VARCHAR(30) DEFAULT '' COMMENT '第三方配送状态' AFTER `city_delivery_price`;
[MODIFY] 订单主表 (eb_store_order)
新增字段以存储客户可见的追踪链接
ALTER TABLE `eb_store_order` ADD COLUMN `delivery_tracking_url` VARCHAR(500) DEFAULT '' COMMENT '配送追踪链接(第三方)' AFTER `delivery_id`;
[MODIFY] WMS 出库单模型 app/model/wms/WmsDocument.php
新增字段的模型属性声明
+ // 新增字段填充
+ protected $append = ['city_delivery_type', 'city_delivery_order_id', 'city_delivery_tracking_url', ...];
改动量:约 10 行
[MODIFY] WMS 出库单 DAO app/dao/wms/WmsDocumentDao.php
搜索条件中增加按配送类型筛选
+ // 支持按 city_delivery_type 筛选出库单
+ if (isset($where['city_delivery_type']) && $where['city_delivery_type'] !== '') {
+ $query->where('city_delivery_type', $where['city_delivery_type']);
+ }
改动量:约 5-8 行
3.7 配置文件
[NEW] config/citydelivery.php
同城配送服务配置
return [
// 默认驱动
'default' => 'lalamove',
// 驱动配置
'stores' => [
'lalamove' => [
'api_key' => '', // Lalamove API Key
'api_secret' => '', // Lalamove API Secret
'market' => 'BR_SP', // 巴西圣保罗市场代码
'base_url' => 'https://rest.lalamove.com', // 正式环境
// 'base_url' => 'https://rest.sandbox.lalamove.com', // 测试环境
],
'loggi' => [
'api_key' => '',
'company_id' => '',
'base_url' => 'https://staging.loggi.com/graphql',
],
],
// 仓库发货点配置(可从 WMS 仓库表动态读取)
'warehouse_origin' => [
'lat' => '', // 仓库纬度
'lng' => '', // 仓库经度
'address' => '', // 仓库详细地址
'contact_name' => '华鲜生仓库',
'contact_phone' => '',
],
];
3.8 前端改动
[MODIFY] 管理后台 — 出库单/发货弹窗
改动内容:
├── 发货方式新增选项卡:「第三方同城配送」
├── 选择后展示:
│ ├── 车辆类型选择(摩托车 / 面包车 / 货车)
│ ├── 「获取报价」按钮 → 调用询价 API
│ ├── 报价展示卡片:
│ │ ├── 配送费:R$ 15.00
│ │ ├── 预计送达:35 分钟
│ │ └── 距离:8.2 km
│ └── 「确认呼叫骑手」按钮 → 调用下单 API
├── 派单成功后展示:
│ ├── 骑手姓名、电话、车牌号
│ ├── 实时追踪链接(可点击新窗口打开)
│ └── 「取消配送」按钮(骑手接单前可取消)
└── 出库单列表新增「配送类型」筛选列(自建 / Lalamove / Loggi)
[MODIFY] 管理后台 — 系统设置
新增「同城配送配置」页面:
├── 配送平台选择(Lalamove / Loggi)
├── API Key / Secret 输入框
├── 市场代码设置(默认 BR_SP)
├── Webhook URL 展示(供配置到 Lalamove 后台)
├── 仓库发货地址配置(地址 / 经纬度 / 联系人 / 电话)
└── 配送费承担策略(平台承担 / 用户支付 / 按比例分担)
[MODIFY] 用户端(H5 / 小程序)— 订单详情页
改动内容:
├── 物流信息区域新增「查看骑手位置」按钮
│ → 点击后在 WebView 中打开第三方追踪链接 (shareLink)
├── 显示骑手信息卡片:
│ ├── 骑手姓名
│ ├── 骑手电话(一键拨号)
│ └── 车牌号
└── 配送状态时间轴:
├── 🟢 商家已发货
├── 🟡 骑手已接单 (Pedro, 摩托车 ABC-1234)
├── 🔵 骑手已取货
└── ✅ 已送达
四、本地化与基础适配改动
优先级:🟡 P1 — 上线前必须完成
4.1 时区与货币
[MODIFY] .env
[APP]
- DEFAULT_TIMEZONE = Asia/Shanghai
+ DEFAULT_TIMEZONE = America/Sao_Paulo
[MODIFY] 系统配置 / 后台设置
├── 默认货币符号:R$(巴西雷亚尔)
├── 货币格式:巴西使用 1.234,56(点分隔千位,逗号分隔小数)
├── 默认语言:pt-BR(葡萄牙语-巴西)/ zh-CN(中文,后台保留中文)
└── 地址格式:CEP + Rua/Avenida + Número + Complemento + Bairro + Cidade + Estado
4.2 地址管理改动
[MODIFY] app/services/user/UserAddressServices.php
// 现有中国省市区三级地址体系需要适配巴西行政区划
+ // 巴西地址结构:Estado(州) → Cidade(城市) → Bairro(街区) → Rua/Logradouro(街道)
+ // CEP(邮编,格式:XXXXX-XXX)
+ // CPF(个人纳税号,格式:XXX.XXX.XXX-XX,部分配送平台要求)
[MODIFY] app/services/shipping/SystemCityServices.php
// 替换中国省市区数据为巴西 Estado/Cidade/Bairro 数据
+ // 或改用 Google Maps Geocoding API 实现地址自动补全
4.3 短信服务替换
现有系统依赖中国短信服务商(一号通、阿里云、腾讯云、创蓝)。在巴西需要替换为本地 SMS 服务或使用 WhatsApp Business API 推送通知。
[NEW] crmeb/services/sms/storage/Twilio.php(或 WhatsApp)
使用 Twilio 发送巴西本地短信 / WhatsApp 消息:
├── sendSms($phone, $content) → 发送葡语短信验证码
├── sendWhatsApp($phone, $content) → 通过 WhatsApp Business API 发送订单通知
└── 替代场景:注册验证码、支付成功通知、发货通知、配送到达通知
五、WMS 流程优化(最小改动)
优先级:🟢 P2 — 优化项
现有 WMS 模块已非常完善,仅需微调以适配华鲜生的实际操作流程。
5.1 预分装管理与条码打印
[MODIFY] app/adminapi/controller/v1/wms/Storage.php(入库控制器)
+ // 入库完成后,自动触发条码标签打印任务
+ // 调用已有的小票打印机服务(飞鹅云/易联云)打印 SKU 条码标签
+ public function printBarcodeLabel($storageId)
+ {
+ // 读取入库单中的商品列表
+ // 生成条码内容(商品编码 + 重量 + 入库日期)
+ // 通过 Printer 服务发送到标签打印机
+ }
5.2 拣货波次优化
[MODIFY] app/services/wms/WmsWastageServices.php
+ // 新增波次拣货方法:将多个待拣货出库单合并为一个拣货批次
+ public function createPickingWave(array $wastageIds)
+ {
+ // 按库位对商品进行聚合排序
+ // 生成最优拣货路线
+ // 返回拣货清单(按库位顺序)
+ }
六、完整改动文件汇总表
新增文件(10 个)
| # | 文件路径 | 用途 | 优先级 |
|---|---|---|---|
| 1 | crmeb/services/pay/storage/PixPay.php |
PIX 支付驱动 | P0 |
| 2 | crmeb/services/pay/extend/mercadopago/MercadoPagoClient.php |
MercadoPago API 客户端 | P0 |
| 3 | app/api/controller/v1/pay/PixNotifyController.php |
PIX 回调控制器 | P0 |
| 4 | crmeb/services/citydelivery/CityDeliveryInterface.php |
同城配送统一接口 | P0 |
| 5 | crmeb/services/citydelivery/BaseCityDelivery.php |
同城配送基类 | P0 |
| 6 | crmeb/services/citydelivery/CityDelivery.php |
同城配送管理器 | P0 |
| 7 | crmeb/services/citydelivery/storage/Lalamove.php |
Lalamove 驱动 | P0 |
| 8 | crmeb/services/citydelivery/storage/Loggi.php |
Loggi 驱动(预留) | P2 |
| 9 | app/services/wms/CityDeliveryServices.php |
同城配送业务服务 | P0 |
| 10 | app/api/controller/v1/pay/CityDeliveryNotifyController.php |
配送回调控制器 | P0 |
修改文件(18 个)
| # | 文件路径 | 改动内容 | 改动量 |
|---|---|---|---|
| 1 | crmeb/services/pay/Pay.php |
注册 PIX 驱动 | ~5 行 |
| 2 | crmeb/services/pay/BasePay.php |
PIX 终端判断 | ~8 行 |
| 3 | app/services/pay/PayServices.php |
PIX 支付常量与分支 | ~20 行 |
| 4 | app/services/pay/OrderPayServices.php |
PIX 参数装配 | ~15 行 |
| 5 | app/services/pay/PayNotifyServices.php |
PIX 回调处理 | ~12 行 |
| 6 | crmeb/services/pay/storage/V3WechatPay.php |
海外 API 域名+货币 | ~20 行 |
| 7 | crmeb/services/easywechat/v3pay/PayClient.php |
可配置 Base URL | ~8 行 |
| 8 | config/pay.php |
PIX 配置注册 | ~10 行 |
| 9 | app/api/route/v1.php |
PIX + 配送回调路由 | ~10 行 |
| 10 | app/adminapi/route/wms.php |
同城配送路由 | ~12 行 |
| 11 | app/services/wms/WmsWastageServices.php |
集成第三方配送 + 波次拣货 | ~50 行 |
| 12 | app/services/order/StoreOrderDeliveryServices.php |
新增发货模式 type=5 | ~35 行 |
| 13 | app/adminapi/controller/v1/wms/Wastage.php |
同城配送控制器方法 | ~60 行 |
| 14 | app/model/wms/WmsDocument.php |
新字段声明 | ~10 行 |
| 15 | app/dao/wms/WmsDocumentDao.php |
新筛选条件 | ~8 行 |
| 16 | .env |
时区改为巴西 | ~1 行 |
| 17 | app/services/user/UserAddressServices.php |
巴西地址格式适配 | ~30 行 |
| 18 | app/services/shipping/SystemCityServices.php |
巴西行政区划数据 | ~20 行 |
新增配置文件(1 个)
| # | 文件路径 | 用途 |
|---|---|---|
| 1 | config/citydelivery.php |
同城配送平台配置 |
数据库变更(2 张表)
| 表名 | 变更 | 新增字段数 |
|---|---|---|
eb_wms_document |
新增第三方配送信息字段 | 8 个字段 |
eb_store_order |
新增配送追踪链接字段 | 1 个字段 |
前端改动(需 uni-app 源码)
| 终端 | 改动页面 | 内容 |
|---|---|---|
| 用户端 H5/小程序 | 收银台 | 新增 PIX 支付选项 + QR Code 展示 |
| 用户端 H5/小程序 | 订单详情 | 新增骑手追踪 + 配送状态时间轴 |
| 管理后台 | 出库单/发货弹窗 | 第三方配送询价+呼叫+追踪面板 |
| 管理后台 | 系统设置 | PIX 配置 + 同城配送配置页 |
| 管理后台 | 订单列表 | 支付方式增加 PIX 图标显示 |
七、开发顺序与里程碑建议
gantt
title 华鲜生代码开发里程碑
dateFormat YYYY-MM-DD
axisFormat %m/%d
section 第一阶段 (核心支付)
PIX 支付驱动开发 :a1, 2026-08-20, 5d
PIX 前端收银台适配 :a2, after a1, 3d
微信海外支付配置适配 :a3, after a1, 2d
支付联调与测试 :a4, after a2, 3d
section 第二阶段 (同城配送)
Lalamove API 驱动开发 :b1, after a4, 5d
WMS 出库-配送流程打通 :b2, after b1, 4d
后台配送操作界面开发 :b3, after b2, 4d
Webhook 回调与状态同步 :b4, after b3, 3d
用户端追踪页面开发 :b5, after b4, 2d
section 第三阶段 (本地化)
时区/货币/地址本地化 :c1, after a4, 4d
巴西短信/WhatsApp 通知 :c2, after c1, 3d
section 第四阶段 (优化)
波次拣货优化 :d1, after b5, 3d
条码标签打印对接 :d2, after d1, 2d
全流程联调测试 :d3, after d2, 5d
总计代码改动估算:新增约 1,500-2,000 行 PHP 代码 + 前端页面适配。整体开发周期约 7-8 周(1名全职 PHP 开发 + 1名前端开发)。