当前利用运维平台的用户进行沟通时,更多的是依赖微信和邮件关照,而运维平台作为一个整体的产品,也须要能够进行内部沟通的一种做事 - 站内信。

站内信的设计基调

站内信的设计基调取决于用户如何利用站内信:

站内信phpPHP实现站内信 Webpack

用户不会守着运维平台这个页面,等待关照,查看内容,然后跳转到要操作的页面。
也便是说站内信不是第一入口,站内信的实时性意义也不大。
同很多社交网站不同(Facebook,知乎,微博等),用户会守在社交网站的主页面,不断刷新新内容,同时检讨新(紧张是个人私信、别人的回答等,也绝不是为了检讨系统关照)用户会根据邮件关照,决定是否要进入运维平台进行操作如果邮件特殊多,例犹如时有多个工单须要用户处理,用户也会在工单平台供应的“我的待办”页面进行所有事情。
如果邮件被误删了,没有邮件链接直接进入要操作的模块 那么或者通过索要链接/单号的办法,前往指定页面或者直接在干系模块进行搜索

上面的描述都意味着用户基本不会利用站内信,那么在什么样的场合会利用站内信呢?

不发邮件,只发站内信的关照,例如全站关照、编辑操作、Comment操作等当详细模块没有详细的操作记录时,可以通过查看站内信的发生韶光

当前只有产品关照,展示也没有进行归类聚合,往后增加全站关照、mention、like、comment等类型的站内信时,就须要考虑按类型进行聚合了。

二、需求描述

站内信常日须要办理两个需求:用户对用户的站内信,管理员对用户的站内信:即一对一发送管理员对多用户、用户组、全站的站内信:即一对多发送

(还有一种是用户对产品的站内信,例如对某个模块的反馈、疑问之类的)

我们目前的需求是:

1管理员对多用户发送站内信

对用户真实性不做校验

对标题长度、内容长度进行限定(分别是45个字节、150个字节,对应中笔墨符15个、50个)

对收件人的拼音长度进行限定(最长50个字节)

2 用户可以查看自己的站内信

按“全部、已读、未读”过滤

按来源分类:工单平台、资源管理、自动装机、漏洞平台、故障平台。


3 用户可以删除、批量删除站内信

4 用户可以已阅、批量已阅、全部标记为已读 站内信

5 运维平台页面顶部的图标

展示未读数,超过99显示 99+鼠标放上去,会有下拉框,展示最近10条未读(展示“韶光”,“来源”,“标题”)下拉框的底部有两个按钮:“更多”,加载更多未读;“查看全部”,跳转到站内信列表页面(最好另开一个窗口)点击下拉框里的未读,通过弹出框展示详情;然后在未读列表里删除该记录,在数据库里标记为已读,图标的未读数量减一

6 管理员页面:

更新用户

删除

统计数据

增加module

增加站内信类型

发送全站

三、系统设计

功能设计

四、系统流程

发送站内信

读取POST要求的request body校验长度插入数据库返回

获取站内信列表

调用子模块,插入发送给全站或我所属用户组的站内信根据查询条件,返回数据库数据

获取未读站内信数量

调用子模块,插入发送给全站或我所属用户组的站内信返回数量

批量已阅

检讨messageId是不是属于当前用户inbox_message表里把 read 置为1,修正update_time

全部已阅

update inbox_message set “read”=1, “update_time”=now where “receiver_name”=currentUser() and “read” = 0

批量删除

检讨messageId是不是属于当前用户inbox_message表里把 deleted 置为1,修正update_time

全部删除

update inbox_message set “deleted”=1, “update_time”=now where “receiver_name”=currentUser() and “deleted” = 0五、数据库设计

站内信内容表

CREATE TABLE `inbox_message_text` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `title` varchar(128) NOT NULL DEFAULT '', `content` longtext NOT NULL, `create_time` datetime NOT NULL, `update_time` datetime NOT NULL, `send_type` tinyint(4) NOT NULL DEFAULT '0', `creator_name` varchar(255) NOT NULL DEFAULT '', `deleted` tinyint(4) NOT NULL DEFAULT '0', `module_id` bigint(20) NOT NULL, `link` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

站内信本身除了来源(module_name),还有一个纬度的描述,叫类型(message_type),例如安全、活动、做事等,每一大类里,又可以划分子类,例如活动-优惠活动

来源和类型可以是正交关系,即工单平台也可以有活动;来源也可以是类型的一种,称为“产品”

站内信发送表

CREATE TABLE `inbox_message` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `message_text_id` bigint(20) NOT NULL, `receiver_name` varchar(255) NOT NULL DEFAULT '', `read` tinyint(4) NOT NULL DEFAULT '0', `deleted` tinyint(4) NOT NULL DEFAULT '0', `create_time` datetime NOT NULL, `update_time` datetime NOT NULL, PRIMARY KEY (`id`), KEY `inbox_message_receiver_name_deleted_read_id` (`receiver_name`,`deleted`,`read`,`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

来源表

CREATE TABLE `inbox_module` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `code` varchar(128) NOT NULL DEFAULT '', `name` varchar(128) NOT NULL DEFAULT '', `create_time` datetime NOT NULL, `update_time` datetime NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `code` (`code`), UNIQUE KEY `name` (`name`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

六、API设计

发送站内信:POST /v1/message

request body Content-Type: application/json

{ \公众title\"大众: \公众工单审批\"大众, \"大众content\"大众: \"大众XXX提交了变更申请,请审批\"大众, \公众to\"大众: \公众sunzhongyuan,shenli,wangya\"大众, \公众module_name\"大众: \公众工单平台\"大众, \"大众link\公众: \公众xxx\公众}

response

{ \"大众code\"大众: 200, \"大众data\"大众: 32, \公众msg\"大众: \公众OK\"大众}

获取站内信列表:GET /v1/message User-Id: xxx

http://127.0.0.1:10085/v1/message?query=message_text_id.module_id.name:xxx&limit=1

{ \"大众code\"大众: 200, \公众data\"大众: { \"大众data\"大众: [ { \"大众id\公众: 1, \"大众message_text\"大众: { \"大众id\"大众: 1, \"大众title\"大众: \"大众title 2\"大众, \"大众content\公众: \"大众content 2\"大众, \公众create_time\"大众: \"大众2018-01-12 11:13:48\公众, \"大众update_time\公众: \公众2018-01-12 11:13:48\公众, \"大众send_type\"大众: 1, \"大众creator_name\"大众: \"大众sysadmin\"大众, \"大众deleted\"大众: 0, \公众link\公众: \"大众xxx\公众, \"大众Messages\"大众: null, \"大众module\公众: { \"大众id\公众: 4, \"大众code\"大众: \"大众secure\"大众, \"大众name\公众: \"大众xxx\公众, \"大众create_time\公众: \"大众2018-01-11 15:38:01\公众, \公众update_time\"大众: \"大众2018-01-11 15:38:01\"大众, \"大众MessageTexts\公众: null } }, \公众receiver_name\"大众: \"大众xxx\公众, \公众read\"大众: 0, \"大众deleted\公众: 0, \"大众create_time\"大众: \"大众2018-01-12 11:13:48\公众, \"大众update_time\"大众: \公众2018-01-12 11:13:48\"大众 } ], \"大众total\"大众: 2 }, \"大众msg\公众: \"大众OK\"大众}

注:

返回数据的个数是由 limit 限定,而 total 是符合query条件的总数(用于分页)

目前没有发送用户组、全站的行为,如果有的话,在获取列表接口里,增加一步“插入所有发送给我所在用户组,或发给全站的,且我自己的站内信列表里没有记录到的站内信”

获取未读站内信数量:GET /v1/message/unread_count

response

{ \公众code\"大众: 200, \"大众data\"大众: 29, \"大众msg\"大众: \"大众OK\"大众}

获取单个站内信内容:GET /v1/message/:id

{ \"大众code\公众: 200, \"大众data\公众: { \公众id\公众: 2, \"大众message_text\公众: { \公众id\"大众: 2, \"大众title\"大众: \"大众title 2\"大众, \"大众content\公众: \公众content 3\"大众, \"大众create_time\公众: \公众2018-01-12 11:37:54\公众, \"大众update_time\"大众: \"大众2018-01-12 11:37:54\"大众, \公众send_type\公众: 1, \公众creator_name\公众: \公众sysadmin\公众, \"大众deleted\"大众: 0, \"大众link\公众: \公众\"大众, \"大众Messages\"大众: null, \"大众module\"大众: { \公众id\"大众: 4, \"大众code\"大众: \"大众secure\"大众, \公众name\"大众: \公众xxx\公众, \"大众create_time\"大众: \"大众2018-01-11 15:38:01\"大众, \"大众update_time\"大众: \公众2018-01-11 15:38:01\公众, \"大众MessageTexts\公众: null } }, \"大众receiver_name\"大众: \"大众xxx\"大众, \公众read\"大众: 1, \"大众deleted\"大众: 0, \"大众create_time\"大众: \"大众2018-01-12 11:37:54\"大众, \公众update_time\"大众: \"大众2018-01-22 17:33:20\"大众 }, \"大众msg\"大众: \"大众OK\"大众}

已阅、批量已阅站内信:PUT /v1/read_messages/:messageIds

response

{ \"大众code\公众: 200, \"大众data\"大众: \"大众OK\"大众, \"大众msg\"大众: \"大众OK\公众}

全部已阅 PUT:/v1/read_all_messages

response 同上

删除、批量删除站内信:PUT /v1/delete_messages/:messageIds

response 同上

全部删除站内信:PUT /v1/delete_all_messages

response 同上

获取消息来源列表:GET /v1/module

response

{ \"大众code\公众: 200, \"大众data\"大众: [ { \"大众id\"大众: 1, \"大众code\"大众: \"大众worksheet\"大众, \"大众name\"大众: \"大众工单平台\"大众, \"大众create_time\公众: \公众2018-01-11 15:21:38\"大众, \"大众update_time\公众: \"大众2018-01-11 15:21:38\公众, \"大众MessageTexts\"大众: null }, { \"大众id\"大众: 2, \"大众code\"大众: \公众cmdb\"大众, \公众name\"大众: \"大众资源管理\"大众, \"大众create_time\"大众: \"大众2018-01-11 15:22:28\公众, \"大众update_time\"大众: \"大众2018-01-11 15:22:28\公众, \"大众MessageTexts\"大众: null }, ... ], \公众msg\"大众: \"大众OK\公众}

七、测试把稳点

1 发送站内信

纯接口收件用户以逗号分割,真实性不做校验收件用户有长度校验,50个字节title content 有长度校验,分别是45,150个字节module_name 是一个列表,必须从这里选一个

2 其他接口都可以通过前端页面测试

八、优化

未读列表可以加上粗体显示,已读则是普通字体对站内信进行分类,打上不同纬度的标签,方便过滤、搜索、屏蔽用户可以设置许可吸收的站内信的来源管理员可以对全站、全站职员、全站的属性进行增编削查,比如撤销某个站内信,让所有人都看不见管理员可以统计站内信的发送数量、各产品的利用情形、被读的比例、被读的韶光、被读的办法(点开还是批量操作),等

九、关键功能点设计

右上角的图标行为

1 点击图标,展示最近的N条未读

展示下拉框实时获取最近N条未读N可以为5~10,详细数值取决于下拉框的高度限定当未读数不敷N时,下拉框能自适应高度如果没有未读,展示”暂无新”停滞每10秒的获取未读数接口

2 下拉框里,展示来源、韶光(相对现在的韶光:10分钟前)、title

向下滑动下拉框,展示更多未读(只获取id小于已展示列表里的最小id,即不获取点击图标后新来的)

3 点击下拉框里的某一个

下拉框不消失落依然停滞每10秒的获取未读数接口未读数减1未读列表删除当前(slice)展示弹出框

4 弹出框展示的来源、韶光(绝对韶光)、title、content

5 关闭弹出框或者点击外围:

弹出框消逝下拉框不消失落可以连续点击某一个未读

6 再次点击下拉框和图标的外围

下拉框消逝清空已有的未读列表规复每10秒的获取未读数接口

7 再次点击图标,重新回到#1状态

阿里云的图标行为是:

刷新页面的时候才会要求一次未读数,之后不再定时刷新(当然也可能是刷新韶光间隔比较长,没创造;又或者采取了 socket 的办法,建立了一个长链接)hover图标,即显示未读的下拉框点击图标,进入站内信管理页面,默认是“未读”

4 点击未读,新开一个Tab,展示该的详情(detail页面),原Tab内容不变,即没有未读数减一,也没从下拉框里删除刚点击的

5 最多展示5条,只要不刷新页面,就一贯是这5条

6 没有滚动更多的功能,只有查看更多,点击进入站内信管理页面,默认是“未读”

和点击图标的差异是:点击图标直接当前页面跳转到站内信管理页面,点击“查看更多”会新建一个Tab

7 多了一个“接管管理”的按钮,当前页面跳转到站内信管理页面,但是默认即“基本吸收管理”

隐蔽浏览器进度条

每10秒的获取未读数接口,会触发浏览器展示进度条,导致分散用户把稳力,要把这个进度条隐蔽掉。

其他刷新页面的行为不受影响。

参考文档

《站内信需求背景及需求剖析的全过程》

《站内信功能设计》

《站内信的实现:数据库的设计》

《站内信的实现思路表的设计》

《Web网站关照系统设计》

举两个例子,怎么样写好代码

最经典的算法,献给正在口试道路上的你

如果你现在在口试PHP的道路上,看看口试根本题吧