Преглед на файлове

feat(shipping-template): 实现运费模板管理功能

- 新增运费模板的创建、读取、更新和删除接口
- 完善运费模板规则表结构,支持默认区域和特殊区域配置
- 调整数据库迁移文件,优化表字段定义和索引设置- 更新路由配置,统一管理运费模板相关API路径
- 增加运费模板前端API调用方法,支持数据格式化处理
-重构运费模板管理页面,整合创建与编辑功能- 移除旧版独立的创建、编辑和选择模板组件
- 添加模板关联关系查询逻辑,支持业务实体绑定运费模板- 优化特殊区域地区信息存储结构,使用JSON格式保存地区编码和名称
- 实现运费模板列表获取接口,支持按业务类型和ID筛选可用模板
runphp преди 5 месеца
родител
ревизия
7381d0e1d8

+ 1 - 2
database/migrations/20251010100000_create_shipping_templates_table.php

@@ -5,8 +5,7 @@ class CreateShippingTemplatesTable extends \Phinx\Migration\AbstractMigration
     public function change()
     {
         $table = $this->table('shipping_templates');
-        $table->setId('id')
-            ->addColumn('name', 'string', ['limit' => 100, 'comment' => '模板名称'])
+        $table->addColumn('name', 'string', ['limit' => 100, 'comment' => '模板名称'])
             ->addColumn('calc_method', 'string', ['limit' => 20, 'comment' => '计费方式: piece(按件), weight(按重量), volume(按体积)'])
             ->addColumn('unit', 'string', ['limit' => 10, 'comment' => '单位: 件,g,kg,cm3,m3', 'default' => 'piece'])
             ->addColumn('status', 'integer', ['limit' => 1, 'comment' => '状态: 0(禁用), 1(启用)', 'default' => 1])

+ 5 - 2
database/migrations/20251010100100_create_shipping_template_rules_table.php

@@ -1,6 +1,9 @@
 <?php
 
-class CreateShippingTemplateRulesTable extends \Phinx\Migration\AbstractMigration
+use think\migration\Migrator;
+use think\migration\db\Column;
+
+class CreateShippingTemplateRulesTable extends Migrator
 {
     public function change()
     {
@@ -11,7 +14,7 @@ class CreateShippingTemplateRulesTable extends \Phinx\Migration\AbstractMigratio
             ->addColumn('first_price', 'decimal', ['precision' => 10, 'scale' => 2, 'comment' => '首件/首重/首体积费用'])
             ->addColumn('next_price', 'decimal', ['precision' => 10, 'scale' => 2, 'comment' => '续件/续重/续体积费用'])
             ->addColumn('area_type', 'string', ['limit' => 20, 'comment' => '区域类型: default(默认), special(特殊区域)'])
-            ->addColumn('sort', 'integer', ['comment' => '排序', 'default' => 100])
+            ->addColumn('area_name', 'string', ['limit' => 100, 'comment' => '区域名称,如:偏远地区、江浙沪等', 'null' => true])
             ->addColumn('regions', 'json', ['comment' => '地区信息(JSON格式,省级行政区划,包含地区编码和名称)', 'null' => true])
             ->addTimestamps('create_time', 'update_time')
             ->addIndex(['template_id'])

+ 1 - 2
database/migrations/20251010100200_create_shipping_template_relations_table.php

@@ -8,8 +8,7 @@ class CreateShippingTemplateRelationsTable extends Migrator
     public function change()
     {
         $table = $this->table('shipping_template_relations');
-        $table->setId('id')
-            ->addColumn('template_id', 'integer', ['comment' => '运费模板ID'])
+        $table->addColumn('template_id', 'integer', ['comment' => '运费模板ID'])
             ->addColumn('biz_type', 'string', ['limit' => 50, 'comment' => '业务类型: goods(商品), category(商品分类), shop(店铺)等'])
             ->addColumn('biz_id', 'integer', ['comment' => '业务实体ID'])
             ->addTimestamps('create_time', 'update_time')

+ 5 - 2
route/admin.php

@@ -3,8 +3,11 @@ declare(strict_types=1);
 
 
 use think\facade\Route;
-
+use SixShop\ShippingTemplate\Controller\ShippingTemplateController;
 // Admin路由
-// 路由前缀: /admin/six-shop-shipping-template//
+// 路由前缀: /admin/shipping_template
 // 如果需要登录请添加认证中间件auth
 // ->middleware(['auth'])
+
+// 运费模板相关路由
+Route::resource('', ShippingTemplateController::class)->middleware(['auth']);

+ 5 - 3
route/api.php

@@ -3,8 +3,10 @@ declare(strict_types=1);
 
 
 use think\facade\Route;
-
+use SixShop\ShippingTemplate\Controller\ShippingTemplateController;
 // API路由
-// 路由前缀: /api/six-shop-shipping-template//
+// 路由前缀: /api/shipping_template/
 // 如果需要登录请添加认证中间件auth
-// ->middleware(['auth'])
+// ->middleware(['auth'])
+
+// 运费模板相关路由

+ 291 - 0
src/Controller/ShippingTemplateController.php

@@ -0,0 +1,291 @@
+<?php
+declare(strict_types=1);
+
+namespace SixShop\ShippingTemplate\Controller;
+
+use SixShop\ShippingTemplate\Enum\ShippingTemplateAreaTypeEnum;
+use SixShop\ShippingTemplate\Model\ShippingTemplateModel;
+use SixShop\ShippingTemplate\Model\ShippingTemplateRelationModel;
+use SixShop\ShippingTemplate\Model\ShippingTemplateRuleModel;
+use think\Request;
+use function SixShop\Core\success_response;
+use function SixShop\Core\error_response;
+
+class ShippingTemplateController
+{
+    /**
+     * 获取运费模板列表
+     * 根据业务类型和业务ID返回可用的运费模板列表,供前端下拉框使用
+     * 并标识出当前选中的模板
+     *
+     * @param Request $request
+     * @return \think\response\Json
+     */
+    public function index(Request $request)
+    {
+        $bizType = $request->get('biz_type/s', '');
+        $bizId = $request->get('biz_id/d', 0);
+
+        // 参数验证
+        if (empty($bizType) || $bizId <= 0) {
+            return error_response('参数错误:biz_type和biz_id不能为空且biz_id必须大于0');
+        }
+
+        // 获取所有启用的运费模板
+        $templates = ShippingTemplateModel::where('status', 1)
+            ->order('sort', 'asc')
+            ->order('id', 'asc')
+            ->select();
+
+        // 获取当前业务实体关联的模板ID
+        $relatedTemplateId = ShippingTemplateRelationModel::getTemplateIdByBiz($bizType, $bizId);
+
+        // 构造返回数据
+        $result = [];
+        foreach ($templates as $template) {
+            $result[] = [
+                'id' => $template->id,
+                'name' => $template->name,
+                'calc_method' => $template->calc_method->value,
+                'calc_method_text' => $template->calc_method->toString(),
+                'unit' => $template->unit,
+                'selected' => $relatedTemplateId == $template->id // 标识是否为当前选中模板
+            ];
+        }
+
+        return success_response($result);
+    }
+
+    /**
+     * 新增运费模板
+     *
+     * @param Request $request
+     * @return \think\response\Json
+     */
+    public function save(Request $request)
+    {
+        // 获取参数
+        $name = $request->param('name', '');
+        $calcMethod = $request->param('calc_method', '');
+        $unit = $request->param('unit', '');
+        $sort = $request->param('sort', 100);
+        $defaultRule = $request->param('default_rule', []);
+        $specialAreas = $request->param('special_areas', []);
+
+        // 参数验证
+        if (empty($name)) {
+            return error_response('模板名称不能为空');
+        }
+
+        if (empty($calcMethod)) {
+            return error_response('计费方式不能为空');
+        }
+
+        // 开始事务
+        $templateModel = new ShippingTemplateModel();
+        $templateRuleModel = new ShippingTemplateRuleModel();
+
+
+        // 保存模板信息
+        $template = $templateModel->save([
+            'name' => $name,
+            'calc_method' => $calcMethod,
+            'unit' => $unit,
+            'sort' => $sort,
+            'status' => 1
+        ]);
+
+        if (!$template) {
+            return error_response('保存模板失败');
+        }
+
+        $templateId = $templateModel->id;
+
+        // 保存默认规则
+        if (!empty($defaultRule)) {
+            $defaultRuleData = [
+                'template_id' => $templateId,
+                'first' => $defaultRule['first'] ?? 1,
+                'first_price' => $defaultRule['first_price'] ?? 0,
+                'next_price' => $defaultRule['next_price'] ?? 0,
+                'area_type' => 'default',
+                'area_name' => '默认区域'
+            ];
+
+            $rule = new ShippingTemplateRuleModel();
+            if (!$rule->save($defaultRuleData)) {
+                return error_response('保存默认规则失败');
+            }
+        }
+
+        // 保存特殊区域规则
+        if (!empty($specialAreas)) {
+            foreach ($specialAreas as $area) {
+                $areaData = [
+                    'template_id' => $templateId,
+                    'first' => $area['first'] ?? 1,
+                    'first_price' => $area['first_price'] ?? 0,
+                    'next_price' => $area['next_price'] ?? 0,
+                    'area_type' => 'special',
+                    'area_name' => $area['name'] ?? '',
+                    'regions' => !empty($area['regions']) ? json_encode($area['regions']) : null
+                ];
+
+                $rule = new ShippingTemplateRuleModel();
+                if (!$rule->save($areaData)) {
+                    return error_response('保存特殊区域规则失败');
+                }
+            }
+        }
+
+        return success_response([
+            'id' => $templateId
+        ], '模板创建成功');
+
+    }
+
+    /**
+     * 更新运费模板
+     *
+     * @param Request $request
+     * @return \think\response\Json
+     */
+    public function update(Request $request)
+    {
+        // 获取参数
+        $id = $request->param('id', 0);
+        $name = $request->param('name', '');
+        $calcMethod = $request->param('calc_method', '');
+        $unit = $request->param('unit', '');
+        $sort = $request->param('sort', 100);
+        $defaultRule = $request->param('default_rule', []);
+        $specialAreas = $request->param('special_areas', []);
+
+        // 参数验证
+        if ($id <= 0) {
+            return error_response('模板ID不能为空');
+        }
+
+        if (empty($name)) {
+            return error_response('模板名称不能为空');
+        }
+
+        if (empty($calcMethod)) {
+            return error_response('计费方式不能为空');
+        }
+
+        // 查找模板
+        $templateModel = ShippingTemplateModel::find($id);
+        if (!$templateModel) {
+            return error_response('指定的模板不存在');
+        }
+
+
+        // 更新模板信息
+        $templateModel->save([
+            'name' => $name,
+            'calc_method' => $calcMethod,
+            'unit' => $unit,
+            'sort' => $sort
+        ]);
+
+        // 删除原有的规则
+        ShippingTemplateRuleModel::where('template_id', $id)->delete();
+
+        // 保存默认规则
+        if (!empty($defaultRule)) {
+            $defaultRuleData = [
+                'template_id' => $id,
+                'first' => $defaultRule['first'] ?? 1,
+                'first_price' => $defaultRule['first_price'] ?? 0,
+                'next_price' => $defaultRule['next_price'] ?? 0,
+                'area_type' => 'default',
+                'area_name' => '默认区域'
+            ];
+
+            $rule = new ShippingTemplateRuleModel();
+            if (!$rule->save($defaultRuleData)) {
+                return error_response('保存默认规则失败');
+            }
+        }
+
+        // 保存特殊区域规则
+        if (!empty($specialAreas)) {
+            foreach ($specialAreas as $area) {
+                $areaData = [
+                    'template_id' => $id,
+                    'first' => $area['first'] ?? 1,
+                    'first_price' => $area['first_price'] ?? 0,
+                    'next_price' => $area['next_price'] ?? 0,
+                    'area_type' => 'special',
+                    'area_name' => $area['name'] ?? '',
+                    'regions' => !empty($area['regions']) ? json_encode($area['regions']) : null
+                ];
+
+                $rule = new ShippingTemplateRuleModel();
+                if (!$rule->save($areaData)) {
+                    return error_response('保存特殊区域规则失败');
+                }
+            }
+        }
+
+        return success_response([
+            'id' => $id
+        ], '模板更新成功');
+    }
+
+    /**
+     * 读取运费模板详情
+     *
+     * @param Request $request
+     * @return \think\response\Json
+     */
+    public function read(int $id)
+    {
+        // 查找模板
+        $templateModel = ShippingTemplateModel::with('template_rule_list')->find($id);
+        if (!$templateModel) {
+            return error_response('指定的模板不存在');
+        }
+
+        // 查找规则
+        $rules = $templateModel->template_rule_list;
+
+        return success_response([
+            'id' => $id,
+            'name' => $templateModel->name,
+            'calc_method' => $templateModel->calc_method,
+            'unit' => $templateModel->unit,
+            'sort' => $templateModel->sort,
+            'default_rule' => $rules->filter(function($rule) {
+                return $rule->area_type === ShippingTemplateAreaTypeEnum::DEFAULT;
+            })->first(),
+            'special_areas' => $rules->filter(function($rule) {
+                return $rule->area_type === ShippingTemplateAreaTypeEnum::SPECIAL;
+            })->values()
+        ], '模板详情读取成功');
+    }
+
+    /**
+     * 删除运费模板
+     *
+     * @param Request $request
+     * @return \think\response\Json
+     */
+    public function delete(int $id)
+    {
+        // 删除模板
+        $templateModel = ShippingTemplateModel::with('template_rule_list')->find($id);
+        if (!$templateModel) {
+            return error_response('指定的模板不存在');
+        }
+
+        // 删除规则
+        $templateModel->template_rule_list()->delete();
+
+        // 删除模板
+        $templateModel->delete();
+
+        return success_response([], '模板删除成功');
+    }
+}

+ 5 - 0
src/Model/ShippingTemplateModel.php

@@ -38,4 +38,9 @@ class ShippingTemplateModel extends Model
             ]
         ];
     }
+
+    public function templateRuleList()
+    {
+        return $this->hasMany(ShippingTemplateRuleModel::class, 'template_id', 'id');
+    }
 }

+ 2 - 0
src/Model/ShippingTemplateRuleModel.php

@@ -15,6 +15,7 @@ use think\Model;
  * @property float $first_price 首件/首重/首体积费用
  * @property float $next_price 续件/续重/续体积费用
  * @property ShippingTemplateAreaTypeEnum $area_type 区域类型
+ * @property string $area_name 区域名称
  * @property string $regions 地区信息(JSON格式)
  * @property string $create_time 创建时间
  * @property string $update_time 更新时间
@@ -28,6 +29,7 @@ class ShippingTemplateRuleModel extends Model
             'pk' => 'id',
             'type' => [
                 'area_type' => ShippingTemplateAreaTypeEnum::class,
+                'regions' => 'array'
             ]
         ];
     }