Skip to content

商城运费开发文档

概述

商城运费功能是针对 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_typetinyint(4)0运费类型:0=包邮,1=统一运费,2=运费模板
mall_express_tpl_idint(11)0运费模板ID(预留功能)
mall_express_feedecimal(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',
];

注意: 运费字段为可选字段,不在 addedit 场景中强制验证,因为只有 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)

扩展开发

运费模板功能

运费模板功能目前为预留功能,可以通过以下方式扩展:

  1. 创建运费模板表
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='商城运费模板表';
  1. 实现 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;
}

注意事项

  1. 字段可选性:运费相关字段为可选字段,非 Mall 类型店铺不需要这些参数
  2. 数据精度:运费金额使用 decimal(20,4) 类型,支持4位小数精度
  3. 策略选择:默认使用取最高运费策略,可根据业务需求调整
  4. 扩展性:运费模板功能预留了扩展接口,便于后续功能开发
  5. 性能考虑:运费计算在订单结算时进行,建议缓存常用计算结果

相关文件

  • 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 - 数据库结构