本篇主要明确配捐系统的概念和具体实现,包括数据结构设计、逻辑关系分析等。
什么是配捐?
配捐的概念诞生于1954年,由美国通用基金会创造。截止2016年,通用的总计配捐总额达到3800万美元。最初只是赞助员工母校的贫困学生,之后逐渐延伸到其他公益领域,也带动了其他企业加入配捐大潮。
网上释义: 自己找吧;
我的释义: 配捐是一种公益活动,参与用户的某种公益行为在满足活动合约中设定的捐款条件后,会触发活动的参与企业以用户的名义为项目捐款。简单来说就是"你出力,我出钱"。
常见的配捐有以下几种形式:
- 分享配捐:用户分享成功一次,公益企业捐出一定数量的$。
- 捐款配捐:用户捐款多少,公益企业就按一定比例捐出多少。
从业务本质上来说,配捐实际上属于一种活动,所以在做系统设计时应当作活动来设计。
数据模型设计
通常「活动」是在后台配置,包括:发布、修改、下线、上线活动。那我们先大概确定下「活动」的相关数据结构。
配捐活动的主要结构如下:
活动类型表「activity_type」
id: {type: 'integer', primaryKey: true, autoIncrement:true} //活动类型ID
activityType: {type: 'string', required: true} //活动类型:分享配捐|捐款配捐|…
createdAt:{type: 'timestamp', required: true}
活动类型不可删除;
活动表「activity」
id: {type: 'integer', primaryKey: true, autoIncrement:true} //活动ID
activityTypeID: {type: ‘integer', required: true} //活动类型ID:
activityName: {type: ‘integer', required: ture} //活动名称, 如:分享配捐第一期
activityImages: {type: ‘text', required: false} //活动图片/封面
startTime: {type: ‘timestamp', required: ture} //活动起始时间
endTime: {type: ‘timestamp', required: ture} //活动结束时间
createdAt: {type: 'timestamp', required: true} //活动创建时间
updatedAt: {type: 'timestamp', required: true} //活动修改时间
remark: {type: ‘text', required: false} //活动规则备注
state: {type: ‘integer', required: true} //活动状态
配捐活动明细表「Activity_matching_gift」
id: {type: 'integer', primaryKey: true, autoIncrement:false} //活动ID
donationAmount: {type: 'decimal(11,2)', required: true} //配捐金额
donationProportion: {type: 'string', required: true} //配捐比例
Donors: {type: 'string', required: true} //配捐参与企业, json字符串 {“charity1”,”charity2”,”charity3”,"…"}
后台界面上根据活动类型加载活动明细表。
活动期间和活动结束后均不得修改活动内容,如果要修改只可以在活动之前修改。
在具体实现时我们还需要考虑配捐与用户、活动、分享、订单等系统之间的逻辑关系。既然讲到实现,那我们就要明确到底要实现什么。
先拿「分享配捐」来说吧。从产品需求中得知有以下几点:
- 用户登录&分享成功后,触发企业捐款;但是在捐款列表中显示的是分享用户的相关信息。由于参与的第三方企业不能做到实时捐款,所以会在捐款列表中标记XX机构将会配捐多少。
- 一个用户一天之内可以分享多次,但是企业一天只配捐一次,不管该用户分享了多少次。
实现过程中的问题和解决方案:
- 捐款列表是已支付的订单。用户分享后要在捐款列表中立刻显示分享用户的信息,而用户只是分享并没有实际捐款,如何解决这个问题?
解决方案是为该用户创建一个订单金额为0的订单,即空订单。 - 第三方企业不能做到实时捐款,那么就要求订单和待配捐的任务必须要有一个关联,以便系统可以异步定时处理这些配捐任务。那么用户-活动-分享-订单之间到底如何建立关系合适呢?是否可以根据分享订单查询企业是否真实捐款了呢?
- 前端捐款列表页面如何做到对于不同的捐款活动展示不同的样式风格呢?
其实「2」和「3」的解决方案是同一个。让我们进一步分析下:
- [x] 用户-参与-活动-分享
用户参与,参与什么呢?参与活动,什么活动呢?分享捐款活动,在活动中做了什么事呢?分享!
- [x] 企业-参与-活动-捐款-订单
企业参与,参与什么呢?参与和用户同样的活动,什么活动呢?分享捐款活动,在活动中做了什么事呢?捐款,生成捐款订单!
现在,我们把用户参与活动的事件及流程,抽象在一张“活动事件表”里。
活动事件表「Activity_event」
id: {type: 'integer', primaryKey: true, autoIncrement:true}
userID: {type: 'string', required: true} //用户ID
activityID: {type: 'integer', required: true} //活动ID
activityTypeID: {type: 'integer', required: true} //活动类型ID
userEventID: {type: 'integer', required: true} //用户事件ID,这个事件可能是分享也可能是别的,因活动类型而定;用户分享ID|...
remark: {type: 'string', required: false} //备注
createdAt:{type: 'timestamp', required: true}
state: {type: 'integer', required: true} //活动事件状态,未完成|已完成
「活动事件表」里即记录了活动关系,也记录了待处理的异步任务。后期与配捐的企业结算也需要这张表。
活动事件订单表「Activity_event_order」
id: {type: 'integer', primaryKey: true, autoIncrement:true}
eventID: {type: 'integer', primaryKey: true, autoIncrement:true} //活动事件表ID
orderID: {type: 'string', required: true} // 订单ID,如果是分享事件,那么这里可能是用户分享后生成的空订单ID,也可能是企业配捐的订单ID
remark: {type: 'string', required: false} //备注,比如可以标注订单的性质,share|matchingGift
createdAt:{type: 'timestamp', required: true}
为什么需要「活动事件订单表」呢?因为不同类型活动的事件,或同一种事件,今天可能是对订单有影响,明天可能是对积分有影响。所以必须把具体被影响的对象抽象出来。「活动事件订单表」表示这个“事件”是对订单有影响,记录的是事件和订单的关系。
如果一个分享订单对应有两个企业配捐,那么这个表一个产生3条记录。一个用户分享的空订单ID,两个企业捐款的订单ID,三个都对应同一个事件ID。
最后 「订单表」 关联 「活动事件订单表」 和 「活动事件表」 就可以解决上面 「2」和「3」 的问题。
这样设计的优点就是从数据结构层做到系统解耦,既不需要修改订单表、分享表和活动表又可以灵活扩展。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。