任务打卡系统

最近在做一个任务打卡系统。

流程大概是这样。 活动报名---》组队---》开启任务---》完成任务---》展示排名。

已经基本完成,这里做个简单总结

1 需求

1.1 该打卡系统,分为两部分。

  • 内部打卡。是自己使用,需要报名,
  • 外部打卡。第三方使用,不需要报名。

因此该打卡系统需支持扩展。

即要把打卡的流程给抽离出来,可以接入任何一个第三方。

做区分很简单,只需通过两个字段

  • model_type 需要接入的第三方的类型
  • activity_id 需要接入的第三方的数据id

1.2 组队模块

队长创建小组,队员扫描二维码,加入团队,达到指定人数,可开启任务。

1.3 任务模块

小组队员扫码或者提交密匙成功后,该小组即可进入下一任务。

2 数据字典

2.1 组队模块

两张表 user_teamsuser_teams

user_teams 记录队长创建的小组


id `` 
activity_id `第三方数据id` 
model_type `第三方类型` 
user_id `队长id` 
name `小组名字` 
slug`小组唯一标识符` 
person_count_limit `小组人数` 
status `小组状态` 
created_at `小组创建时间` 
dissolved_at `解散时间` 
completed_at `小组开启任务时间` 

users_teams 记录队员加入小组

id 
activity_id `第三方数据id` 
model_type `第三方类型` 
user_id `队员id` 
team_id `小组id` 
status  `用户在小组中的状态` 
joined_at `加入时间`
exit_at `退出时间`

2.1 任务模块

两张表 activity_tasksteams_tasks

activity_tasks 记录第三方的打卡任务

id
activity_id `第三方数据id` 
model_type `第三方类型`
type `任务的类型`
name `任务的名字`
slug `任务唯一标识符`
img `任务图片`
key_lists `任务密匙列表`
key_used_lists `已用的密匙列表`

teams_tasks 记录小组进行到哪一个打卡任务

id
activity_id  `第三方数据id` 
model_type `第三方类型`
team_id  `小组id` 
task_id `任务id` 
status `小组在该任务的状态` 
started_at `小组开启该任务的时间` 
completed_at `小组完成该任务的时间` 

模型

打卡模型 (1).png

3 后端业务实现

3.1 小组模块

小组中有三个数前端拿到,就可以 //todo。

  • $usersTeam 用户在团队中的状态,对应users_team表中的一条记录
  • $team 小组的相关信息,对应 user_team表中的一条记录
  • $users 队员列表

 list($usersTeam,$team)  = $user->hasTeam($activityId,$modelType);

 //团队用户
  $users = $team->users();

基本上每个 api请求都要用到上面的三个数据。因此在设计业务的的时候,抽离出最小的关键的对象。接下来,就是这些对象的该怎么组合的问题了,就形成了,不同的业务逻辑。

3.2 任务模块

任务中有四个数据,前端拿到,就可以 //todo

  • $currentTask 当前正在进行的任务
  • $teamTasks 已经完成的任务和正在进行的任务,对应team_tasks表中的几条条记录
  • $tasks 分配的所有任务,由$taskIds所得。
  • $taskIds 分配的任务id 对应 user_team表的taskIds
list($teamTasks,$tasks,$taskIds,$currentTask) = $user->teamTasks($modelType,$activityId);

任务模块主要的是如何给小组分配任务。比如说,不希望所有小组都从相同的任务开始。

比如说有 1,2,3,4,5,6 个任务

第一个小组分配任务顺序 1,2,3,4,5,6

第一个小组分配任务顺序 2,3,4,5,6,1

第一个小组分配任务顺序 3,4,5,6,1,2

依次的不断循环

伪代码实现

//所有任务的id
$taskIds=[];

//已选所有任务的第一个id
$taskFirstIds=[];
//统计每个任务被分配的数量
$taskIdsCount = array_count_values($taskFirstIds);
//从小到大排序
asort($taskIdsCount);
//选取第一个renwuid 作为开始
$taskStartId=array_key_first($taskIdsCount);

$key=array_search($taskStartId,$taskIds);

//最终结果
$ids =array_merge(array_slice($taskIds,$key),array_slice($taskIds,0,$key));

4 前端业务实现

有一个可以总结的,小组和任务状态管理,使用到了有限状态机查看

小组和任务状态比较多。

比如小组,在数据库中的状态

  • inviting 正在邀请
  • starting 已完成
  • automatic_dissolution 自动解散
  • dissolution 解散

由于前端要把后端对应的状态映射到相对应的显示,对应到前端的状态转换,就比较多了

* create 正在创建
* inviting 正在邀请
* starting 已完成,正在开始任务
* edit 管理小组

把每一个状态的改变统一管理起来,逻辑清晰且可控。

new StateMachine({
            transitions: [
                { name: 'start', from: 'none',   to: 'create'  },
                { name: 'invite',  from: 'none',  to: 'inviting' },
                { name: 'invite',  from: 'create',  to: 'inviting' },
                { name: 'invite',  from: 'edit',  to: 'inviting' },
                { name: 'started', from: 'inviting',  to: 'starting' },
                { name: 'started', from: 'edit',  to: 'starting' },
                { name: 'started', from: 'none',  to: 'starting' },
                { name: 'dissolve', from: 'inviting',  to: 'create' },
                { name: 'dissolve', from: 'edit',  to: 'create' },
                { name: 'edit', from: 'inviting',  to: 'edit'    },

            ],
            methods: {
                onEnterCreate(lifecycle){
                    //todo
                },
                onEnterInviting(lifecycle){
                    //todo
                },
                onEnterStarting(lifecycle){
                     //todo

                },
                onEnterEdit(lifecycle){
                     //todo
                }
            }
        });

流程图

流程图.png

Posted in php, 前端, 后端 on Aug 08, 2019

请登录 登录 评论!