系统设计:活动室申请系统

活动室申请系统是一个广泛存在的系统,如学生想要组织活动,需要学校的场地,那么他们会去向有权限的老师申请场地,然后在规定时间去规定的场地活动,如果这个场地是一个有锁的房间,那么可能还需要找门卫要钥匙开门,通常还需要出示申请通过的证明……

这是一件逻辑简单的事务,随着办公互联网化、无纸化办公的需要,活动室申请系统应运而生。

我们可以抽象地描述刚才的事务:

首先有若干场地、空间、房间(Room)需要挂载在系统上;

然后申请人(Applicant)提出申请(Application);

然后管理员(Administrator)审批申请;

然后门卫(GateKeeper)核对申请并提供进入场地的方法;

由于这个东西与线下资源结合紧密,自动提供进入场地的设施需(自动门卫)要嵌入式设备的支持,目前暂不考虑。

可以看到,场地是最根本的东西,没有场地,那后面所说的一切都不重要了,但场地绝不是这个系统第一个诞生的对象。

实现

这个后端的系统已经用NodeJS实现,并以MIT协议开源:function-x/room-application
前后端耦合度非常低,可以说后端仅仅是提供了一套API。
前后端通过AJAX,JSON格式传递信息。

对象建模

这个系统内具有三类对象:用户(User:包括申请人、管理员、门卫)、场地(Room)、申请表(Application)。

用户

用户有一个属性:用户组——来区别申请人、管理员或者是门卫。

我们假设管理员与门卫是坚决站在场地所有人一方的,管理员具有系统基本上所有的权力(但他们可能不能修改系统代码),门卫则仅仅有管理线下场地的权力。

另外,隐藏有一个可以操作系统后台代码文件的人(通常是运维人员),这不属于系统内部,不作考虑(尽管它可能对系统具有无上的权力)。

但开放注册的用户群,不能排除存在恶意用户的情况,必须严加提防。

场地

一个门卫可以管多个场地,但一个场地最多只能归一个门卫管。

因此场地应该具有一个门卫的引用属性,但可以为空,因为有一些场地是不需要门卫的。

场地有不重复的名称、描述、门卫三个属性,我们假设一个场地的合法门卫只能是一个人,避免责任分摊;他可以授权给其他人(线下),但一旦发生门禁意外,由门卫负责财产损失。

申请表

申请表是由用户提出的,是申请人为了场地的使用权限而提交的表单。

我们假设,申请至少要自拟一个标题,并作详细的使用场地的描述。

除此之外,要提供“具体申请的是哪个场地”、“是谁申请的”、“在哪个时间段使用”这样的信息。

管理员可以审核这个申请,给出“通过”或者“拒绝”的判断,或者来回切换,至于如何发送通知,可以借助Email,或者发送短信等(通知的部分我没有实现)。

可以通过算法判断当时场地是否被使用:

在用户新增申请时,判断这个区间内是否已有已经通过审核的申请:如果有,申请提交直接失败;如果没有,加入数据库。
在管理员审核申请时,当审批“通过”时,将其他所有具有公共区间的申请全部自动审批为“拒绝”。

对于一个审核通过的申请,会自动生成一个口令,只有申请人对应的 门卫可以看到,他们可以在线下直接通过对口令的方式获取信任。

这个口令有两个设计原则:

  1. 对口令要方便,不能生成一个长的Hash码,让人直接比对,这不现实。
  2. 口令不能根据申请信息生成,要加入足够的随机因子,使得口令不能被别人直接算出来。

API 文档

基本API

初始化

在刚刚部署的时候,一个管理员都没有,因此需要一个API来创建第一个管理员,以便后续操作。

{
    url: '/init',
    type: 'post',
    data: {
        username: String, // 设定管理员账户
        password: String  // 设定管理员密码
    }
}

这个API会检查当前的管理员数量,如果是0才会添加管理员,否则将返回错误(代码为1)。

注册

注册用户的API

{
    url: '/signup',
    type: 'post',
    data: {
        username: String, // 设定账户
        password: String, // 设定密码
    }
}
登录

登录用户的API

{
    url: '/signin',
    type: 'post',
    data: {
        username: String, // 账户
        password: String, // 密码
    }   
}
查询当前状态

这个API会返回当前用户的状态(会直接将当前用户的可公开数据回传)

{
    url: '/status',
    type: 'get',
}
登出

用户登出的API

{
    url: '/signout',
    type: 'get'
}

用户类API

列出用户的信息

会列出所有(也可以自定义查询)用户的可公开信息(即隐藏密码),仅有管理员身份的用户可以调用这个API。

{
    url: '/user',
    type: 'get',
    data: any // 自定义查询(筛选条件)
}
查看用户的信息

会列出某用户的可公开信息,所有人可以调用。

{
    url: '/user/:_id', // _id 是用户的唯一标识ID
    type: 'get'
}
更改用户的信息

更改用户的账户、密码等,仅限用户本人与管理员
更改用户的权限组,仅限管理员。

{
    url: '/user/:_id', // _id 是用户的唯一标识ID
    type: 'put',
    data: Any // 自由的查询结构
}
删除用户

仅管理员可以调用。

{
    url: '/user/:_id', // _id 是用户的唯一标识ID
    type: 'delete'
}

场地类API

创建场地

准确的说是登记场地,仅管理员可用。

{
    url: '/room',
    type: 'post',
    data: {
        name: String, // 场地名称,不能重复
        description: String, // 场地描述,通常包含场地的具体位置,设施条件等
        gatekeeper: ObjectId // 其门卫的ID,默认为空。
    }
}
列出场地

列出所有场地,所有人可用。

{
    url: '/room',
    type: 'get'
}
更改场地

更改某场地的名称或描述或门卫,仅管理员可用。

{
    url: '/room/:_id', // _id 为场地的唯一标识ID
    type: 'put',
    data: Any // 为新建场地的数据格式的子集。
}
删除场地

仅管理员可用。

{
    url: '/room/:_id', // _id 为场地的唯一标识ID
    type: 'put',
}

申请类

提交申请

新建一个申请并提交,仅登录的用户可用。

{
    url: '/application',
    type: 'get',
    data: {
        title: String, // 申请的标题,通常是指活动的主题
        description: String, // 活动的具体描述
        room: ObjectId, // 场地的唯一标识ID,必选
        start: Number, // 开始时间,数字格式
        end: Number, // 结束时间,数字格式
    }
}
查看申请列表

所有人均可以自定义查询条件,至少要给出要查询的场地ID。
默认会查询从现在开始24小时内的所有已通过的申请。

{
    url: '/application',
    type: 'get',
    data: {
        room: ObjectId, // 场地的唯一标识ID,必选
        start: Number, // 开始时间,数字格式
        end: Number, // 结束时间,数字格式
        status: String // 状态:仅接受'accepted', 'failed', 'pending' 三种值
    }
}
查看某申请(口令)

按照申请的ID来查看申请,如果申请通过并且查看人是申请者或者是对应的门卫,则会显示口令

{
    url: '/application/:_id', // _id 为申请的唯一标识ID
    type: 'get',
}
更改申请状态(审批)

仅管理员可用,可以更改申请的状态(通过或者不通过)

{
    url: '/application/:_id', // _id 为申请的唯一标识ID
    type: 'put',
    data: {
        status: String // 只接受'accepted'与'failed'
    }
}
删除申请

仅管理员可用。

{
    url: '/application/:_id', // _id 为申请的唯一标识ID
    type: 'delete'
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值