zoukankan      html  css  js  c++  java
  • 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 < 1)
                {
                    FollowExpireDays = 1;
                }
                List<CustomerInfo> list = BLLFactory<Customer>.Instance.GetUnContactList(FollowExpireDays, LoginUserInfo.ID.ToString());
                return list;
            }

    在业务层,我们只需要构造我们的过滤条件获取到用户的数据,并处理它状态就可以了。

                    condition.AddCondition("LastContactDate", today.AddDays(-1 * FollowExpireDays), SqlOperator.LessThanOrEqual);
                    condition.AddCondition("Deleted", 0, 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 < 1)
                    {
                        FollowExpireDays = 1;
                    }
    
                    condition.AddCondition("Grade", alarmInfo.Grade, SqlOperator.Equal);
                    condition.AddCondition("LastContactDate", today.AddDays(-1 * FollowExpireDays), SqlOperator.LessThanOrEqual);
                    condition.AddCondition("Deleted", 0, 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);
        }

    注意上这些,使用枚举就一切都顺利了。

  • 相关阅读:
    EcShop二次开发学习方法
    [ 产品经理 ] 互联网产品经理常用软件及工作平台
    Tengine – Nginx衍生版
    把PHP大牛记下来,方便以后关注
    看了极光推送技术原理的几点思考
    centos磁盘满了,查找大文件并清理
    LNMP一键安装包 PHP自动升级脚本
    微信红包系统设计 & 优化
    程序员每天每周每月每年该做的事
    php中$_REQUEST、$_POST、$_GET的区别和联系小结
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/3946504.html
Copyright © 2011-2022 走看看