Winform开发框架中实现信息阅读状态的显示和存储
在很多项目中,可能会有要求对一些数据的阅读状态进行记录,用户阅读过或者未阅读过,都做不同的标识,方便了解数据的状态。如在我的客户关系管理系统中,对于客户的状态进行跟踪,如果最近联系时间超过配置天数的,那么特别显示出来。类似的应用场景,还有很多地方应用到,如对于通知公告、流程记录、内部信息等状态查看都可能是这样的类型。那么如何解决这些通用的需求呢,是需要每个都设置一个表来记录这些状态吗?
1、应用需求场景
前面说了,我们可能在一些数据上需要记录不同用户的阅读状态,如下面是我客户关系管理系统里面,对于最近没有联系的客户列表,其中对他们的查看状态进行特别显示。
当然,在我们业务系统里面,可能还有其他类似的场景。

对于这些相似的需求我们把这些应用场景的状态,用一个表来存储它的数据变化就可以做到了,我们设计一个表TB_InformationStatus来存储这些数据的状态。

上面的Information_ID就是对应不同表数据的ID,Status为我们需要记录的状态,User_ID为对应使用人员,这样对于不同业务表,不同的人员都可以把他们的数据记录起来,供我们处理显示了。
2、功能实现
对于这个信息状态的记录表,我们需要定义几个接口来进行信息的处理。
/// <summary>
/// 设置状态
/// </summary>
/// <param name="UserID">用户ID</param>
/// <param name="InfoType">信息类型</param>
/// <param name="InfoID">信息主键ID</param>
/// <param name="Status">状态:0未读 1已读 </param>
void SetStatus(string UserID, InformationCategory InfoType, string InfoID, int Status); /// <summary>
/// 匹配状态
/// </summary>
/// <param name="UserID">用户ID</param>
/// <param name="InfoType">信息类型</param>
/// <param name="InfoID">信息主键ID</param>
/// <param name="Status">状态:0未读 1已读 </param>
/// <returns></returns>
bool CheckStatus(string UserID, InformationCategory InfoType, string InfoID, int Status); /// <summary>
/// 查看指定的记录是否已读
/// </summary>
/// <param name="UserID">用户ID</param>
/// <param name="InfoType">信息类型</param>
/// <param name="InfoID">信息主键ID</param>
/// <returns></returns>
bool IsReadedStatus(string UserID, InformationCategory InfoType, string InfoID);
我们设计了上面的辅助表TB_InformationStatus来存储这些数据的状态,但并没有改变主表的字段数据,但是我们在显示主表的数据的时候,联合处理一下就可以了。
以客户信息为例,我们联合处理,获得的数据,依旧是客户信息的列表,如下代码所示。
/// <summary>
/// 获取用户的最近未联系客户列表
/// </summary>
/// <returns></returns>
private List<CustomerInfo> GetUnContactList()
{
string KeyName = "FollowExpireDays";
int FollowExpireDays = config.AppConfigGet(KeyName).ToInt32();
if (FollowExpireDays < )
{
FollowExpireDays = ;
}
List<CustomerInfo> list = BLLFactory<Customer>.Instance.GetUnContactList(FollowExpireDays, LoginUserInfo.ID.ToString());
return list;
}
在业务层,我们只需要构造我们的过滤条件获取到用户的数据,并处理它状态就可以了。
condition.AddCondition("LastContactDate", today.AddDays(- * FollowExpireDays), SqlOperator.LessThanOrEqual);
condition.AddCondition("Deleted", , SqlOperator.Equal);//不显示删除的
condition.AddCondition("Creator", userId, SqlOperator.Equal);//仅仅选择该用户的记录
string where = condition.BuildConditionSql().Replace("Where", "");
List<CustomerInfo> list = baseDal.Find(where);
foreach (CustomerInfo info in list)
{
bool readed = BLLFactory<InformationStatus>.Instance.IsReadedStatus(userId, InformationCategory.客户联系, info.ID);
info.Data1 = readed ? "已读" : "未读";
}
上面代码的Data1是我们实体类基类的属性,这里我们很方面用它来记录状态,否则我们需要把实体类集合转换为DataTable类型了。
这样我们返回的数据就带有这个记录的阅读状态,我们只需要在显示的时候,把Data1属性的别名修改一下就可以了。
/// <summary>
/// 绑定列表数据
/// </summary>
private void BindData()
{
this.winGridViewPager1.DisplayColumns = displayColumns;
this.winGridViewPager1.ColumnNameAlias = BLLFactory<Customer>.Instance.GetColumnNameAlias();//字段列显示名称转义
this.winGridViewPager1.AddColumnAlias("Data1", "查看状态"); List<CustomerInfo> list = GetUnContactList();
this.winGridViewPager1.DataSource = new WHC.Pager.WinControl.SortableBindingList<CustomerInfo>(list);
this.winGridViewPager1.PrintTitle = "未联系客户信息列表";
}
3、功能扩展
为了更有效展示不同类型客户的记录,我们可能需要设置普通客户7天需要跟进,VIP客户5天跟进,高级VIP客户3天跟进的时效,也就是对于同一个记录,不同属性类型,可能要求不同。
我们如果要实现这个需求,那么就需要再另外一个表里面记录客户类型和间隔天数的数据了。

然后在业务逻辑层处理返回未联系客户的时候,对他们进行分别处理,获取数据后进行合并,如下代码所示。
/// <summary>
/// 获得指定间隔时间内未联系的客户列表
/// </summary>
/// <param name="unContactDays">和最后联系日期的间隔天数</param>
/// <param name="userId">当前用户</param>
/// <returns></returns>
public List<CustomerInfo> GetUnContactList(int unContactDays, string userId)
{
List<CustomerInfo> listAll = new List<CustomerInfo>(); //根据用户配置的信息进行逐条处理,然后合并记录
List<CustomerAlarmInfo> alarmList = BLLFactory<CustomerAlarm>.Instance.FindByUser(userId);
foreach (CustomerAlarmInfo alarmInfo in alarmList)
{
//如果存在高级查询对象信息,则使用高级查询条件,否则使用主表条件查询
SearchCondition condition = new SearchCondition();
DateTime today = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd"));
int FollowExpireDays = alarmInfo.Days;
if (FollowExpireDays < )
{
FollowExpireDays = ;
} condition.AddCondition("Grade", alarmInfo.Grade, SqlOperator.Equal);
condition.AddCondition("LastContactDate", today.AddDays(- * FollowExpireDays), SqlOperator.LessThanOrEqual);
condition.AddCondition("Deleted", , SqlOperator.Equal);//不显示删除的
condition.AddCondition("Creator", userId, SqlOperator.Equal);//仅仅选择该用户的记录 string where = condition.BuildConditionSql().Replace("Where", ""); List<CustomerInfo> list = baseDal.Find(where);
foreach (CustomerInfo info in list)
{
bool readed = BLLFactory<InformationStatus>.Instance.IsReadedStatus(userId, InformationCategory.客户联系, info.ID);
info.Data1 = readed ? "已读" : "未读";
} listAll.AddRange(list);
}
return listAll;
}
对于混合架构上的应用,我们注意到接口的地方,需要使用一个枚举的参数(信息类别名称),我们在接口定义的时候,需要特别声明几个地方,否则容易出现错误。
枚举的对象需要声明一下的。
/// <summary>
/// 信息分类
/// </summary>
[DataContract]
public enum InformationCategory
{
[EnumMember]
客户联系, [EnumMember]
通知公告, [EnumMember]
其他
};
定义的WCF接口,用到了枚举类型的参数,也需要特别声明枚举的类型
[ServiceContract]
[ServiceKnownType(typeof(InformationCategory))]
public interface IInformationStatusService : IBaseService<InformationStatusInfo>
{
/// <summary>
/// 设置状态
/// </summary>
/// <param name="UserID">用户ID</param>
/// <param name="InfoType">信息类型</param>
/// <param name="InfoID">信息主键ID</param>
/// <param name="Status">状态:0未读 1已读 </param>
[OperationContract]
void SetStatus(string UserID, InformationCategory InfoType, string InfoID, int Status); /// <summary>
/// 匹配状态
/// </summary>
/// <param name="UserID">用户ID</param>
/// <param name="InfoType">信息类型</param>
/// <param name="InfoID">信息主键ID</param>
/// <param name="Status">状态:0未读 1已读 </param>
/// <returns></returns>
[OperationContract]
bool CheckStatus(string UserID, InformationCategory InfoType, string InfoID, int Status); /// <summary>
/// 查看指定的记录是否已读
/// </summary>
/// <param name="UserID">用户ID</param>
/// <param name="InfoType">信息类型</param>
/// <param name="InfoID">信息主键ID</param>
/// <returns></returns>
[OperationContract]
bool IsReadedStatus(string UserID, InformationCategory InfoType, string InfoID);
}
注意上这些,使用枚举就一切都顺利了。
Winform开发框架中实现信息阅读状态的显示和存储的更多相关文章
- 在Winform开发框架中,利用DevExpress控件实现数据的快速录入和选择
在实际的项目开发过程中,有好的控件或者功能模块,我都是想办法尽可能集成到我的WInform开发框架中,这样后面开发项目起来,就可以节省很多研究时间,并能重复使用,非常高效方便.在我很早之前的一篇博客& ...
- Winform开发框架中工作流模块之申请单草稿处理
在我们开发工作流模块的时候,有时候填写申请单过程中,暂时不想提交审批,那么可以暂存为草稿,以供下次继续填写或者提交处理,那么这个草稿的功能是比较实用的,否则对于一些填写内容比较多的申请单,每次要重填写 ...
- 参照企业微信审批业务,在Winform开发框架中工作流模块的实现业务审批
目前微信的企业号已经切换到企业微信里面,这个是一个APP程序,提供了很丰富的企业应用,其中包括了业务审批处理,审批业务包括请假.报销.费用.出差等很多个审批场景,在Winform开发框架中工作流模块这 ...
- Winform开发框架中工作流模块的业务表单开发
在我们开发工作流的时候,往往需要设计到具体业务表单信息的编辑,有些是采用动态编辑的,有些则是在开发过程中处理的,各有各的优点,动态编辑的则方便维护各种各样的表单,但是数据的绑定及处理则比较麻烦,而自定 ...
- Winform开发框架中工作流模块的表设计分析
在较早博客随笔里面写过文章<Winform开发框架之简易工作流设计>之后,很久没有对工作流部分进行详细的介绍了,本篇继续这个主题,详细介绍其中的设计.实现及效果给大家,这个工作流在好几年前 ...
- Winform开发框架中工作流模块之审批会签操作(2)
前面随笔介绍了请假申请单和报销申请单两个不同的业务表单的流程处理,一个是单表信息,一个包含明细的主从表信息,后者包含了条件流程的处理,在流程审批中,一般还有一种流程处理就是会签的操作,会签处理是几个审 ...
- Winform开发框架中工作流模块之审批会签操作
在前面介绍了框架中工作流的几个开发过程,本篇随笔重点介绍一下日常审批环节中的具体处理过程,从开始创建表单,以及各个审批.会签过程的流转过程,希望大家对其中流程的处理有一个大概的印象. 1.请假申请表单 ...
- Winform开发框架中实现同时兼容多种数据库类型处理
在很多应用系统里面,虽然一般采用一种数据库运行,但是由于各种情况的需要,可能业务系统会部署在不同类型的数据库上,如果开发的系统能够很方便支持多种数据库的切换,那可以为我们减少很多烦恼,同时提高系统的适 ...
- Winform开发框架中的综合案例Demo
在实际的系统开发中,我们往往需要一些简单的的案例代码,基于此目的我把Winform开发框架中各种闪光点和不错的功能,有些是我们对功能模块的简单封装,而有些则是引入了一些应用广泛的开源组件进行集成使用, ...
随机推荐
- 【读书笔记】.Net并行编程(三)---并行集合
为了让共享的数组,集合能够被多线程更新,我们现在(.net4.0之后)可以使用并发集合来实现这个功能.而System.Collections和System.Collections.Generic命名空 ...
- 安装金山WPS2013造成的HTML5 file.type值异常
处理代码的兼容性是前端攻城师们的家常便饭了,一般是对各种浏览器进行兼容性处理.但是有时候我们也会遭遇到浏览器以外的影响因素,这个是经常会被忽视掉的内容.比如前几天就听说客户端安装迅雷.暴风影音等软件会 ...
- [php入门] 4、HTML基础入门一篇概览
[php入门] 1.从安装开发环境环境到(庄B)做个炫酷的登陆应用 [php入门] 2.基础核心语法大纲 [php入门] 3.WAMP中的集成MySQL相关基础操作 1.HTML的作用 HTML是超文 ...
- MVC5:使用Ajax和HTML5实现文件上传功能
引言 在实际编程中,经常遇到实现文件上传并显示上传进度的功能,基于此目的,本文就为大家介绍不使用flash 或任何上传文件的插件来实现带有进度显示的文件上传功能. 基本功能:实现带有进度条的文件上传功 ...
- Objective-C实现发短信和接电话
发短信: [[UIApplication sharedApplication]openURL:[NSURL URLWithString:@"sms://10000"]]; 打电话: ...
- DDD~基础设施层~续
回到目录 在之前写的DDD~基础设施层文章中,提到了UnitOfWork,它里面有一些方法,但经过项目证明,不应该有Save和IsExplicitSubmit,而这个工作单元只起到了数据上下文统一的作 ...
- EF架构~为IEnumerable接口添加增删查等操作,原因是IEnumerable导航属性更放心
回到目录 对EF开发来说,导航属性肯定都用过,事实上,它是由VS IDE工具根据你的数据库关系结构自动生成的外键属性,在类视图中可以看到相关属性,它是以外键表名来标识的,如果是一对多的关系,那么,它会 ...
- EF架构~CodeFirst自关联表的插入
回到目录 这个文章对之前EF的一个补充,对于一些自关联表的添加,如果你建立了表约束确实有这种问题,一般主键为整形自增,父ID为可空,这时,在添加时如果不为ID赋值,结果就会出错. 错误: 无法确定依赖 ...
- JQuery向导插件Step——第一个阉割版插件
如果使用过JQuery Steps的朋友一定会发现这个插件有一个缺点,就是页面在第一次进入的时候,会进行一次很明显的DOM重绘--页面会闪一下. 尤其是前端代码比较庞大的时候,效果更为明显. 为了解决 ...
- 手把手教你搭建SpringMVC——最小化配置
为什么需要Spring MVC 最开始接触网页的时候,是纯的html/css页面,那个时候还是用Dreamweaver来绘制页面. 随着网站开发的深入,开始学习servlet开发,记得最痛苦的就是se ...