Appearance
商城运费开发文档
概述
商城运费功能是针对 mall
类型商品的运费计算系统,支持包邮、统一运费、运费模板三种模式。本文档详细说明如何开发和使用商城运费功能。
扩展说明: 当前系统仅支持包邮和统一运费两种模式,运费模板功能为预留接口。如需支持其他运费计算类型(如店铺统一运费规则、按重量、按地区、按件数等),可在 DeshangMallExpressService.php
类中自行扩展实现。
数据库字段
商城运费功能基于商品表的三个核心字段:
sql
-- 商品表 #__tbl_goods 中的运费相关字段
`mall_express_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'mall快递类型 0包邮 1统一运费 2模板',
`mall_express_tpl_id` int(11) NOT NULL DEFAULT '0' COMMENT 'mall快递运费模板ID(可拓展)',
`mall_express_fee` decimal(20,4) NOT NULL DEFAULT '0.0000' COMMENT 'mall固定运费',
字段说明
字段名 | 类型 | 默认值 | 说明 |
---|---|---|---|
mall_express_type | tinyint(4) | 0 | 运费类型:0=包邮,1=统一运费,2=运费模板 |
mall_express_tpl_id | int(11) | 0 | 运费模板ID(预留功能) |
mall_express_fee | decimal(20,4) | 0.0000 | 固定运费金额(单位:元) |
核心服务类
DeshangMallExpressService
商城运费计算的核心服务类,位于 php-server/app/deshang/service/order/DeshangMallExpressService.php
主要方法
1. calculateMallExpressFee()
计算商城运费的主入口方法。
php
/**
* 计算商城运费
*
* @param array $store_info 店铺信息
* @param array $goods_list 商品列表
* @param array $address 收货地址
* @return array 运费计算结果
*/
public function calculateMallExpressFee($store_info, $goods_list, $address)
参数说明:
$store_info
: 店铺信息数组$goods_list
: 商品列表数组,每个商品包含goods
对象$address
: 收货地址数组
返回值:
php
[
'shipping_amount' => 10.00, // 最终运费金额
'express_type' => 1, // 运费类型
'express_fee' => 10.00, // 运费金额
'express_tpl_id' => 0, // 运费模板ID
'calculation_details' => [ // 计算详情
'type' => 'max_fee',
'description' => '取最高运费',
'fee' => 10.00,
'strategy' => 'max_fee'
]
]
2. setExpressStrategy()
设置运费计算策略。
php
/**
* 设置运费计算策略
*
* @param string $strategy 策略类型
* @return $this
*/
public function setExpressStrategy($strategy)
支持的策略:
DeshangMallExpressService::STRATEGY_MAX_FEE
- 取最高运费DeshangMallExpressService::STRATEGY_SUM_FEE
- 运费相加
运费计算策略
1. 取最高运费策略(默认)
php
$mallExpressService = new DeshangMallExpressService();
$mallExpressService->setExpressStrategy(DeshangMallExpressService::STRATEGY_MAX_FEE);
计算逻辑:
- 遍历所有商品,计算每个商品的运费
- 取所有商品运费中的最高值
- 类似淘宝/天猫的运费计算方式
示例:
php
// 商品A: 包邮 (mall_express_type: 0) → 运费: 0元
// 商品B: 统一运费 (mall_express_type: 1, mall_express_fee: 10) → 运费: 10元
// 商品C: 统一运费 (mall_express_type: 1, mall_express_fee: 15) → 运费: 15元
// 取最高运费策略结果: max(0, 10, 15) = 15元
2. 运费相加策略
php
$mallExpressService = new DeshangMallExpressService();
$mallExpressService->setExpressStrategy(DeshangMallExpressService::STRATEGY_SUM_FEE);
计算逻辑:
- 遍历所有商品,计算每个商品的运费
- 将所有商品运费相加
- 类似京东的运费计算方式
示例:
php
// 商品A: 包邮 (mall_express_type: 0) → 运费: 0元
// 商品B: 统一运费 (mall_express_type: 1, mall_express_fee: 10) → 运费: 10元
// 商品C: 统一运费 (mall_express_type: 1, mall_express_fee: 15) → 运费: 15元
// 运费相加策略结果: 0 + 10 + 15 = 25元
运费类型详解
1. 包邮 (mall_express_type: 0)
特点:
- 商品免运费
mall_express_fee
字段无效mall_express_tpl_id
字段无效
计算逻辑:
php
case 0: // 包邮
$result['shipping_amount'] = 0;
$result['calculation_details'] = [
'type' => 'free_shipping',
'description' => '商品包邮',
'fee' => 0
];
break;
2. 统一运费 (mall_express_type: 1)
特点:
- 使用固定的运费金额
mall_express_fee
字段有效mall_express_tpl_id
字段无效- 支持数量计算:运费 = 固定运费 × 商品数量
计算逻辑:
php
case 1: // 统一运费
$result['shipping_amount'] = $express_fee * $quantity;
$result['calculation_details'] = [
'type' => 'fixed_fee',
'description' => '统一运费',
'fee' => $result['shipping_amount']
];
break;
示例:
php
// 商品设置: mall_express_type=1, mall_express_fee=10.00
// 购买数量: 3件
// 计算结果: 10.00 × 3 = 30.00元
3. 运费模板 (mall_express_type: 2)
特点:
- 使用运费模板计算
mall_express_tpl_id
字段有效mall_express_fee
字段无效- 预留功能,可根据重量、件数、地区等计算
计算逻辑:
php
case 2: // 运费模板
$result['shipping_amount'] = $this->calculateTemplateFee([
'express_type' => $express_type,
'express_fee' => $express_fee,
'express_tpl_id' => $express_tpl_id
], [$goods_item], $address) * $quantity;
$result['calculation_details'] = [
'type' => 'template_fee',
'description' => '运费模板计算',
'fee' => $result['shipping_amount']
];
break;
在订单结算中的使用
DeshangOrderCheckoutService 集成
在 DeshangOrderCheckoutService.php
中,商城运费计算集成在订单结算流程中:
php
case 'mall':
// 商城 运费
$mallExpressService = new DeshangMallExpressService();
$expressResult = $mallExpressService->calculateMallExpressFee(
$store['store_info'],
$store['goods_list'],
$address
);
$shipping_amount = $expressResult['shipping_amount'];
// 保存运费计算详情到订单交付信息中
$order_delivery_info['mall_express'] = $expressResult;
break;
数据结构要求
商品列表数据结构必须包含运费相关字段:
php
$goods_list = [
[
'goods' => [
'mall_express_type' => 1, // 运费类型
'mall_express_tpl_id' => 0, // 运费模板ID
'mall_express_fee' => '10.0000', // 固定运费
// ... 其他商品字段
],
'quantity' => 2, // 商品数量
// ... 其他字段
],
// ... 更多商品
];
前端商品编辑
Vue 组件集成
在商品编辑页面 vue-element-admin/src/pages-store/platform/mall/views/goods/goods/edit.vue
中:
vue
<!-- 快递类型 -->
<el-form-item label="快递类型" prop="mall_express_type">
<el-radio-group v-model="formData.mall_express_type">
<el-radio :value=0>包邮</el-radio>
<el-radio :value=1>统一运费</el-radio>
<!-- <el-radio :value=2>运费模板</el-radio> -->
</el-radio-group>
</el-form-item>
<!-- 运费模板ID -->
<el-form-item label="运费模板ID" prop="mall_express_tpl_id" v-if="formData.mall_express_type === 2">
<el-input-number v-model="formData.mall_express_tpl_id" :min="0" placeholder="运费模板ID(预留功能)" disabled />
<div class="text-sm text-gray-500 mt-1">此功能暂未开放,请选择其他运费方式</div>
</el-form-item>
<!-- 固定运费 -->
<el-form-item label="固定运费" prop="mall_express_fee" v-if="formData.mall_express_type === 1">
<el-input-number
v-model="formData.mall_express_fee"
:min="0"
:precision="4"
:step="0.01"
placeholder="请输入固定运费金额"
/>
<div class="text-sm text-gray-500 mt-1">单位:元</div>
</el-form-item>
数据初始化
javascript
const formData = reactive({
// ... 其他字段
mall_express_type: 0, // 0包邮 1统一运费 2模板
mall_express_tpl_id: 0, // 运费模板ID
mall_express_fee: 0, // 固定运费
// ... 其他字段
});
// 加载商品数据时
const loadGoodsData = async (goodsId: string | number) => {
// ... 其他逻辑
formData.mall_express_type = res.data.mall_express_type || 0;
formData.mall_express_tpl_id = res.data.mall_express_tpl_id || 0;
formData.mall_express_fee = res.data.mall_express_fee || 0;
// ... 其他逻辑
};
后端数据验证
TblGoodsValidator 验证规则
在 php-server/app/deshang/service/goods/validate/TblGoodsValidator.php
中:
php
protected $rule = [
// ... 其他规则
// [Mall类型商品]运费相关字段验证
'mall_express_type' => 'in:0,1,2',
'mall_express_tpl_id' => 'integer|egt:0',
'mall_express_fee' => 'float|egt:0',
];
protected $message = [
// ... 其他消息
// 运费相关字段错误信息
'mall_express_type.in' => '快递类型值不正确,只能是0(包邮)、1(统一运费)、2(运费模板)',
'mall_express_tpl_id.integer' => '运费模板ID必须是整数',
'mall_express_tpl_id.egt' => '运费模板ID不能小于0',
'mall_express_fee.float' => '固定运费必须是数字',
'mall_express_fee.egt' => '固定运费不能小于0',
];
注意: 运费字段为可选字段,不在 add
和 edit
场景中强制验证,因为只有 Mall 类型店铺需要这些参数。
开发示例
1. 基本使用
php
use app\deshang\service\order\DeshangMallExpressService;
// 创建运费计算服务
$mallExpressService = new DeshangMallExpressService();
// 设置运费策略(可选,默认为取最高运费)
$mallExpressService->setExpressStrategy(DeshangMallExpressService::STRATEGY_MAX_FEE);
// 计算运费
$expressResult = $mallExpressService->calculateMallExpressFee(
$store_info, // 店铺信息
$goods_list, // 商品列表
$address // 收货地址
);
// 获取运费金额
$shipping_amount = $expressResult['shipping_amount'];
2. 不同策略对比
php
// 商品列表示例
$goods_list = [
[
'goods' => [
'mall_express_type' => 0, // 包邮
'mall_express_fee' => '0.0000'
],
'quantity' => 1
],
[
'goods' => [
'mall_express_type' => 1, // 统一运费
'mall_express_fee' => '10.0000'
],
'quantity' => 2
],
[
'goods' => [
'mall_express_type' => 1, // 统一运费
'mall_express_fee' => '15.0000'
],
'quantity' => 1
]
];
// 取最高运费策略
$mallExpressService->setExpressStrategy(DeshangMallExpressService::STRATEGY_MAX_FEE);
$result1 = $mallExpressService->calculateMallExpressFee($store_info, $goods_list, $address);
// 结果: shipping_amount = 15.00 (max(0, 20, 15))
// 运费相加策略
$mallExpressService->setExpressStrategy(DeshangMallExpressService::STRATEGY_SUM_FEE);
$result2 = $mallExpressService->calculateMallExpressFee($store_info, $goods_list, $address);
// 结果: shipping_amount = 35.00 (0 + 20 + 15)
扩展开发
运费模板功能
运费模板功能目前为预留功能,可以通过以下方式扩展:
- 创建运费模板表
sql
CREATE TABLE `#__mall_express_template` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`template_name` varchar(100) NOT NULL COMMENT '模板名称',
`template_rules` text COMMENT '模板规则JSON',
`is_enabled` tinyint(1) DEFAULT '1' COMMENT '是否启用',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商城运费模板表';
- 实现 calculateTemplateFee() 方法
php
private function calculateTemplateFee($express_settings, $goods_list, $address)
{
$template_id = $express_settings['express_tpl_id'] ?? 0;
if ($template_id <= 0) {
return 0;
}
// TODO: 实现运费模板计算逻辑
// 1. 根据template_id查询运费模板
// 2. 根据商品重量/件数/体积计算
// 3. 根据收货地址地区计算
// 4. 返回计算结果
return 0;
}
注意事项
- 字段可选性:运费相关字段为可选字段,非 Mall 类型店铺不需要这些参数
- 数据精度:运费金额使用
decimal(20,4)
类型,支持4位小数精度 - 策略选择:默认使用取最高运费策略,可根据业务需求调整
- 扩展性:运费模板功能预留了扩展接口,便于后续功能开发
- 性能考虑:运费计算在订单结算时进行,建议缓存常用计算结果
相关文件
php-server/app/deshang/service/order/DeshangMallExpressService.php
- 核心运费计算服务php-server/app/deshang/service/order/DeshangOrderCheckoutService.php
- 订单结算服务php-server/app/deshang/service/goods/validate/TblGoodsValidator.php
- 商品验证器-php-server/app/platform/mall/app/storeapi/controller/goods/MallGoods.php
- Mall商品控制器vue-element-admin/src/pages-store/platform/mall/views/goods/goods/edit.vue
- 商品编辑页面php-server/public/install/db/deshang.sql
- 数据库结构