在线药店网站灵活折扣系统实现:需求与技术疑问咨询
在线药店折扣/优惠系统设计方案
一、需求梳理
你需要实现的折扣系统包含以下类型:
- 指定商品百分比折扣(如指定药品享20%优惠)
- 买X赠Y活动
- 品类专属折扣(如所有维生素享10%优惠)
- 优惠券代码(如SAVE10)
- 限时优惠(含开始与结束日期)
折扣需在Product page、Cart、Invoice三个页面正确展示。
二、核心疑问解答
1. 优惠系统的最佳数据库结构设计方案
采用分层+类型区分的设计,核心表结构如下:
主表:discounts(优惠主信息)
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | INT(11) | 主键,优惠ID |
| discount_type | VARCHAR(50) | 优惠类型:PERCENT_PRODUCT(指定商品折扣)、BUY_X_GET_Y(买赠)、CATEGORY_PERCENT(品类折扣)、COUPON(优惠券) |
| name | VARCHAR(100) | 优惠名称(如"维生素10%折扣") |
| description | TEXT | 优惠描述 |
| start_date | DATETIME | 开始时间(限时优惠必填) |
| end_date | DATETIME | 结束时间(限时优惠必填) |
| is_active | TINYINT(1) | 是否启用 |
| priority | INT(11) | 优惠优先级(解决冲突时用,数值越高优先级越高) |
| exclusive_group | VARCHAR(50) | 互斥组标识(同一组内优惠只能选一个) |
关联表(按类型拆分,避免冗余)
指定商品/品类折扣表
discount_product_category字段名 类型 说明 discount_id INT(11) 关联 discounts.idtarget_type VARCHAR(20) 目标类型: PRODUCT(指定商品)、CATEGORY(品类)target_id INT(11) 商品ID/品类ID discount_value DECIMAL(5,2) 折扣百分比(如20代表20%) 买赠活动表
discount_buy_x_get_y字段名 类型 说明 discount_id INT(11) 关联 discounts.idbuy_product_id INT(11) 需购买的商品ID buy_quantity INT(11) 需购买的数量 get_product_id INT(11) 赠送的商品ID get_quantity INT(11) 赠送的数量 max_get INT(11) 单次订单最多赠送数量(可选) 优惠券表
discount_coupon字段名 类型 说明 discount_id INT(11) 关联 discounts.idcoupon_code VARCHAR(50) 优惠券代码(如SAVE10) discount_value DECIMAL(10,2) 折扣值(可以是百分比或固定金额,需结合类型判断) discount_mode VARCHAR(20) 折扣模式: PERCENT(百分比)、FIXED(固定金额)min_order_amount DECIMAL(10,2) 最低订单金额限制(可选) usage_limit INT(11) 总使用次数限制(可选) user_usage_limit INT(11) 单用户使用次数限制(可选)
订单关联表order_discounts
记录订单实际使用的优惠,用于对账和发票展示:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | INT(11) | 主键 |
| order_id | INT(11) | 关联订单ID |
| discount_id | INT(11) | 关联discounts.id |
| discount_amount | DECIMAL(10,2) | 实际抵扣金额 |
| details | TEXT | 优惠使用详情(如"买2赠1:赠送XX药品1盒") |
2. 折扣计算应在前端还是后端执行?
核心计算必须在后端执行,前端仅做展示和预计算:
- 后端:负责所有优惠规则校验、计算逻辑、最终金额确认,确保数据安全,避免前端篡改金额。比如优惠券有效性、限时优惠时间判断、买赠规则匹配等,都必须在后端完成。
- 前端:仅做用户友好的预展示,比如商品页显示当前可享的折扣、购物车实时展示预估优惠金额,但最终提交订单时必须以后端返回的计算结果为准。
3. 如何避免多种优惠之间的冲突?
通过优先级+互斥规则解决:
- 优先级判断:根据
discounts表的priority字段,数值越高优先级越高,优先应用高优先级优惠。比如优惠券优先级高于品类折扣,品类折扣高于指定商品折扣。 - 互斥组限制:同一
exclusive_group下的优惠只能选一个,比如"全场8折优惠券"和"品类10%折扣"属于同一互斥组,用户只能二选一。 - 明确叠加规则:提前定义允许叠加的优惠类型,比如:
- 允许叠加:指定商品折扣 + 买赠活动(买指定打折商品同时享受买赠)
- 禁止叠加:优惠券 + 品类折扣(同一订单只能用一种)
- 计算顺序控制:先匹配所有符合条件的优惠,再按优先级排序,处理互斥逻辑,最后计算最终金额。
4. 如何构建清晰且可扩展的优惠逻辑架构?
采用策略模式+规则管理器的架构:
- 抽象优惠策略接口:定义统一的
DiscountStrategy接口,包含isEligible()(判断订单是否符合优惠条件)、calculateDiscount()(计算折扣金额)、applyToOrder()(将优惠应用到订单)三个核心方法。 - 按类型实现策略类:
PercentProductDiscountStrategy:处理指定商品百分比折扣BuyXGetYDiscountStrategy:处理买赠活动CategoryPercentDiscountStrategy:处理品类折扣CouponDiscountStrategy:处理优惠券
- 优惠规则管理器:负责加载所有可用优惠策略、根据订单信息匹配符合条件的优惠、处理优先级和互斥逻辑、计算最终优惠金额。
- 可扩展设计:新增优惠类型时,只需新增对应的策略类并注册到管理器即可,无需修改核心逻辑。比如未来要加"满减优惠",只需实现
FullReductionDiscountStrategy即可。
业务层分层设计:
- 数据访问层(DAO):负责数据库交互,获取优惠配置
- 业务逻辑层(Service):调用规则管理器处理优惠计算
- 控制器层(Controller):接收前端请求,返回计算结果
内容的提问来源于stack exchange,提问作者منصور انور
相关产品推荐
相关产品推荐

