Angular13+Laravel多表单折扣规则执行与最大折扣方案问询
后台规则匹配与最大折扣计算方案(Angular13 + Laravel架构)
一、规则存储设计
先把折扣规则结构化存储到数据库,建议新增两张核心表:
forms:存储课程报名表单基础信息(表单ID、名称等)form_discount_rules:存储每套表单对应的折扣规则,核心字段包括:form_id:关联表单IDcondition_expression:JSON格式的条件表达式,示例:{"conditions": [{"field": "A", "operator": "eq", "value": "VIP"}, {"field": "age", "operator": "gte", "value": 25}], "logic": "and"}discount_percent:折扣比例(如10表示10%折扣)priority:可选字段,用于折扣率相同时的规则优先级(数值越高优先级越高)
这种JSON结构能灵活支持多字段的and/or组合条件,后续扩展新字段或逻辑也更方便。
二、规则匹配与最大折扣计算流程
用户填写表单时,后端执行以下步骤:
- 接收前端传递的表单ID和用户输入的字段数据
- 拉取当前表单对应的所有折扣规则(可缓存规则提升性能)
- 逐个解析规则的条件表达式,判断用户输入是否满足规则要求
- 收集所有满足条件的规则折扣率,取最大值作为最终折扣
三、核心实现代码(Laravel)
下面是可直接复用的折扣计算器类:
namespace App\Services; use App\Models\FormDiscountRule; class DiscountCalculator { public function getMaxDiscount(array $userInput, int $formId): float { // 优先从缓存获取规则,缓存失效时从数据库拉取 $rules = cache()->remember("form_discount_rules_{$formId}", 3600, function () use ($formId) { return FormDiscountRule::where('form_id', $formId)->get(); }); $validDiscounts = []; foreach ($rules as $rule) { $condition = json_decode($rule->condition_expression, true); if ($this->checkConditionMatch($userInput, $condition)) { $validDiscounts[] = [ 'percent' => $rule->discount_percent, 'priority' => $rule->priority ?? 0 ]; } } if (empty($validDiscounts)) { return 0.0; } // 先按折扣率降序,再按优先级降序排序,取第一个 usort($validDiscounts, function ($a, $b) { if ($a['percent'] !== $b['percent']) { return $b['percent'] - $a['percent']; } return $b['priority'] - $a['priority']; }); return $validDiscounts[0]['percent'] / 100; // 返回小数形式的折扣(如0.1表示10%) } private function checkConditionMatch(array $userInput, array $condition): bool { $conditions = $condition['conditions'] ?? []; $logic = $condition['logic'] ?? 'and'; $matchResults = []; foreach ($conditions as $cond) { $fieldValue = $userInput[$cond['field']] ?? null; $matchResults[] = $this->compareValues($fieldValue, $cond['operator'], $cond['value']); } return $logic === 'and' ? !in_array(false, $matchResults, true) : in_array(true, $matchResults, true); } private function compareValues($fieldValue, string $operator, $ruleValue): bool { // 统一类型转换,避免字符串和数字比较的误差 if (is_numeric($fieldValue) && is_numeric($ruleValue)) { $fieldValue = (float)$fieldValue; $ruleValue = (float)$ruleValue; } return match ($operator) { 'eq' => $fieldValue == $ruleValue, 'ne' => $fieldValue != $ruleValue, 'gt' => $fieldValue > $ruleValue, 'gte' => $fieldValue >= $ruleValue, 'lt' => $fieldValue < $ruleValue, 'lte' => $fieldValue <= $ruleValue, 'in' => in_array($fieldValue, (array)$ruleValue), 'not_in' => !in_array($fieldValue, (array)$ruleValue), default => false, }; } }
四、优化建议
- 缓存优化:如果表单规则不会频繁修改,将规则缓存到Redis或Laravel文件缓存中,减少数据库查询次数
- 前端辅助校验:为提升用户体验,前端可以根据规则做实时预计算,但最终折扣必须以后端计算结果为准,防止前端篡改
- 规则引擎扩展:如果后续规则复杂度大幅提升(如嵌套条件、自定义函数),可以引入PHP规则引擎库替代自定义解析逻辑,降低维护成本
- 安全校验:禁止在条件表达式中使用可执行代码,所有条件判断通过预定义的运算符实现,避免注入风险
内容的提问来源于stack exchange,提问作者Rajeev Sharma
相关产品推荐
相关产品推荐

