脊柱外科病人资料管理系统的界面设计分析(2)--JOA评分记录的实现

简介:

在上篇随笔《脊柱外科病人资料管理系统的界面设计分析》中介绍了一些常用的界面设计方面的内容,本篇继续上一篇,介绍脊柱外科病人管理系统的JOA评分记录模块的界面设计以及实现方面的内容。

JOA(全称 Japanese Orthopaedic Association Scores for Assessment of Cervical Myelopathy),日本骨科学会(JOA)颈椎病疗效评定标准,用于在脊柱外科的术前术后,对患者身体状况进行量化,并制定相关的护理方案提供依据。JOA评分记录模块,是软件《脊柱外科病人资料管理系统》的一个亮点,能使外科医生或者护士,对患者的信息进行全面的记录和研究参考。

1、JOA评分记录模块的分析

JOA评分记录,有点类似于考题的方式,对各项内容进行分值的评估,每项记录的得分不同,汇总成一个总的得分,用于量化评估,它的分类大致如下所示。

 从上面的文档截图可以看到,评分项目可以分为一个大类(如自觉症状),多个子项目(如下腰痛)这样的组织方式,然后我们需要记录每项的得分,以及所有项目累加的总分。

通过分拆,我们可以把一个记分的题目作为一个控件,每个题目它自己的得分明细可以动态从数据库获取即可,界面控件设计如下所示。

通过上面的分析,我们知道,一个项目大类(如自觉症状)包含了多个子项目(如下腰痛、步态等)这样的题目,也就是多个上面控件的实例,那么我们设计的项目大类控件界面如下所示。

以上的界面,其实就是在一个大的项目大类控件上组合多个子项目控件的效果。

然后,整个JOA评分的界面就是多个上面项目大类的组合了,组合成了一个JOA评分记录模块的控件效果,如下所示。

 最后,我们在第一个文档截图里面看到,JOA评分分为两个方面,一个是术前的,一个是术后的,他们的评分界面完全一样,那么我们可以把它们用两个Tab界面进行分开处理,最后得到的运行界面如下所示。

2、JOA评分记录的逻辑实现

 为了在界面呈现各项分数项目,我们需要在数据库设计一个表JOAItem,用来存储每个评分项目的内容,然后在界面中根据分类进行动态展示。

然后定义一个评分子项目的信息对象ControlItem,作为上面控件的信息对象,方便控件和数据库关联起来,记分或者存储明细到数据库中,代码如下所示。

    /// <summary>
    /// JOA评分项目明细
    /// </summary>
    [DataContract]
    public class ControlItem 
    {    
        /// <summary>
        /// 序号,从1开始
        /// </summary>
        [DataMember]
        public virtual int Seq { get; set; }

        /// <summary>
        /// 分类名称
        /// </summary>
        [DataMember]
        public virtual string Category { get; set; }

        /// <summary>
        /// 项目明细列表(包括项目得分等信息)
        /// </summary>
        [DataMember]
        public virtual List<JOAItemInfo> ItemList { get; set; }

        /// <summary>
        /// 评分项目第一项得分(默认得分)
        /// </summary>
        public virtual decimal DefaultScore
        {
            get
            {
                if (ItemList == null || ItemList.Count == 0)
                {
                    return 0M;
                }
                else
                {
                    return ItemList[0].Score;
                }
            }
        }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public ControlItem() 
        { 
            ItemList = new List<JOAItemInfo>(); 
        }

        /// <summary>
        /// 参数构造函数
        /// </summary>
        /// <param name="seq">序号</param>
        /// <param name="category">分类名称</param>
        /// <param name="itemList">项目明细列表</param>
        public ControlItem(int seq, string category, List<JOAItemInfo> itemList) : this()
        {
            this.Seq = seq;
            this.Category = category;
            this.ItemList = itemList;
        }
    }

在上面的评分控件中,我们整合以上的信息对象作为一个整体,部分代码如下所示。

    public partial class ScoreItemControl : DevExpress.XtraEditors.XtraUserControl
    {
        /// <summary>
        /// 单项的序号,从1开始
        /// </summary>
        public int Seq = 1;

        /// <summary>
        /// 控件绑定的信息
        /// </summary>
        public ControlItem ControlItem { get;set; } 

        /// <summary>
        /// 单项的得分
        /// </summary>
        public decimal Score { get; set; } 

        /// <summary>
        /// 处理分数变化后的事件触发
        /// </summary>
        public event ScoreChangedHandler OnScoreChanged;

       ............................

当我们在评分控件中指定了ControlItem信息后,在控件的Load事件里面,将会动态绑定评分的项目明细,代码如下所示。

        private void ScoreItemControl_Load(object sender, EventArgs e)
        {
            if (ControlItem != null && !this.DesignMode)
            {
                this.lblItemIndex.Text = ControlItem.Seq.ToString();
                this.layoutItem.Text = ControlItem.Category;

                List<CListItem> itemList = new List<CListItem>();
                foreach (JOAItemInfo info in ControlItem.ItemList)
                {
                    itemList.Add(new CListItem(info.ItemDetail, info.Score.ToString()));
                }

                radItemGroup.BindDictItems(itemList);
            }

            if (radItemGroup.Properties.Items.Count > 0)
            {
                this.radItemGroup.SelectedIndex = 0;
            }
        }

除了ControlItem信息对象的绑定,我们还注意到上面的OnScoreChanged事件,它就是为了我们在整个控件中实现分数动态变化的一个事件,这样我们变化任何一个评分项目信息,单项分数和总分都会重新计算一次的事件。

        /// <summary>
        /// 处理分数变化后的事件触发
        /// </summary>
        public virtual void ProcessScoreChanged(int seq, decimal score)
        {
            if (OnScoreChanged != null)
            {
                OnScoreChanged(seq, score);
            }
        }

        private void radItemGroup_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.lblItemScore.Text = string.Format("得分({0})分", this.radItemGroup.EditValue);

            decimal result = 0;
            if (decimal.TryParse(this.radItemGroup.EditValue.ToString(), out result))
            {
                this.Score = result;
                ProcessScoreChanged(Seq, result);
            }
        }

以上代码逻辑就是最小评分控件的一个具体的实现,完成以上这些,还需要完成一个评分项目大类的具体逻辑,它的操作方式和上面差不多,也是引入一个信息对象集合作为背后得分计算的逻辑。

定义的信息对象ProjectItem代码如下所示。

   /// <summary>
   /// JOA评分项目信息
   /// </summary>
    [DataContract]
    public class ProjectItem
    {
        /// <summary>
        /// 序号,从1开始
        /// </summary>
        [DataMember]
        public virtual int Seq { get; set; }

        /// <summary>
        /// 项目名称
        /// </summary>
        [DataMember]
        public virtual string Project { get; set; }

        /// <summary>
        /// 项目明细列表
        /// </summary>
        [DataMember]
        public virtual List<ControlItem> ItemList { get; set; }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public ProjectItem() 
        {
            ItemList = new List<ControlItem>();
        }

        /// <summary>
        /// 评分项目第一项得分总和(默认得分)
        /// </summary>
        public virtual decimal DefaultScore
        {
            get
            {
                if (ItemList == null || ItemList.Count == 0)
                {
                    return 0M;
                }
                else
                {
                    decimal total = 0M;
                    foreach (ControlItem item in ItemList)
                    {
                        total += item.DefaultScore;
                    }
                    return total;
                }
            }
        }

        /// <summary>
        /// 参数化构造函数
        /// </summary>
        /// <param name="seq"></param>
        /// <param name="project"></param>
        /// <param name="itemList"></param>
        public ProjectItem(int seq, string project, List<ControlItem> itemList) : this()
        {
            this.Seq = seq;
            this.Project = project;
            this.ItemList = itemList;
        }
    }

然后该控件的逻辑代码就是结合这个信息对象以及控件的一些事件进行处理了,控件的部分代码如下所示。

    public partial class ScoreProjectControl : DevExpress.XtraEditors.XtraUserControl
    {
        /// <summary>
        /// 项目大类的序号,从1开始
        /// </summary>
        public int ProjectSeq = 1;
        
        /// <summary>
        /// 项目大类的信息 
        /// </summary>
        public ProjectItem ProjectItem { get; set; }

        /// <summary>
        /// 处理分数变化后的事件触发
        /// </summary>
        public event ScoreChangedHandler OnScoreChanged;

        private Dictionary<int, decimal> scoreList = new Dictionary<int, decimal>();//记录单项的得分列表

        ...................

由于每项评分子项目是单独的评分控件,控件的布局采用了FlowLayout布局呈现方式,因此在控件的Load事件代码如下所示。

        private void ScoreProjectControl_Load(object sender, EventArgs e)
        {
            if (ProjectItem != null && !this.DesignMode)
            {
                this.lblProject.Text = string.Format("{0}、{1}", ProjectItem.Seq, ProjectItem.Project);

                this.flowLayoutPanel1.Controls.Clear();
                int index = 1;
                foreach (ControlItem item in ProjectItem.ItemList)
                {
                    ScoreItemControl control = new ScoreItemControl();
                    control.ControlItem = item;
                    control.Seq = index++;
                    control.OnScoreChanged += new ScoreChangedHandler(control_OnScoreChanged);
                    this.flowLayoutPanel1.Controls.Add(control);
                }
            }
        }

同样整个控件也有一个OnScoreChanged 的事件,我们看到,这个和上面介绍的事件操作方式类似,都是一级负责一级的分数处理,具体代码如下所示。

        void control_OnScoreChanged(int seq, decimal score)
        {
            if(!scoreList.ContainsKey(seq))
            {
                scoreList.Add(seq, score);
            }
            else
            {
                scoreList[seq] = score;
            }

            //项目的总分变化
            ProcessScoreChanged(ProjectSeq, this.TotalScores);
        }

以上的控件实现逻辑一步步递推,就能很好实现评分项目的动态呈现,以及控件评分分数的动态变化和总分记录保存,由于涉及的实现细节还比较多,一篇随笔介绍内容太多显得累赘,但是其他控件的实现逻辑和上面的操作方式差不多,在这里就不在一一赘述了,本文主要提供一个这种的实现思路进行JOA评分记录模块的实现,进一步拓展,可以把它应用到考试题目上 ,可以作为动态抽取题目,然后记录测试者的题目选择信息,最后把测试者的答案和标准答案对比得出用户的总分,这样就完成了试题的动态测试案例了。

本文转自博客园伍华聪的博客,原文链接:脊柱外科病人资料管理系统的界面设计分析(2)--JOA评分记录的实现,如需转载请自行联系原博主。



目录
相关文章
|
1月前
|
监控
选择合适的进销存管理系统的重要性
所谓“好马配好鞍”,一个高效、智能的进销存系统不仅可以帮助企业实现库存优化,降低库存成本,还能提升客户满意度和企业运营效率。
16 1
|
6月前
|
开发框架 前端开发 JavaScript
saas模式LIS系统源码,功能模块:前处理、检验、报告、质控、统计分析、两癌筛查
检验流程简单,可自适配,操作简便; 检验界面优雅,支持报告模板多样化,预设报告模板多种多样; 接口标准化,预留标准HIS、仪器数据接入接口; 功能齐全,集齐前处理、检验、报告、质控、统计分析、两癌等模块; SaaS服务,无需部署,开通账号接口快速入门使用; 独立部署简单,全程服务到位; 检验申请签收支持多种来源检验申请、智能判断标本类型和数量、智能合并同一标本; 标本签收支持实时标本进度、自动分配仪器标本号、支持外检标本签收;
saas模式LIS系统源码,功能模块:前处理、检验、报告、质控、统计分析、两癌筛查
|
7月前
|
数据采集 数据可视化 数据挖掘
豆瓣图书评分数据的可视化分析
豆瓣是一个提供图书、电影、音乐等文化产品的社区平台,用户可以在上面发表自己的评价和评论,形成一个丰富的文化数据库。本文将介绍如何使用爬虫技术获取豆瓣图书的评分数据,并进行可视化分析,探索不同类型、不同年代、不同地区的图书的评分特征和规律
118 1
|
11月前
|
BI 数据库
汇总报表怎么做,如何设计实现汇总报表?
汇总报表怎么做,如何设计实现汇总报表?
|
数据可视化
基于销售软件利润表的数据可视化分析:数据+代码+实验报告:
基于销售软件利润表的数据可视化分析:数据+代码+实验报告:
92 0
基于销售软件利润表的数据可视化分析:数据+代码+实验报告:
|
SQL BI Shell
报表统计_广告投放统计_代码实现 | 学习笔记
快速学习报表统计_广告投放统计_代码实现
81 0
报表统计_广告投放统计_代码实现 | 学习笔记
|
开发框架 JavaScript 前端开发
新闻信息管理系统功能展示
新闻信息管理系统功能展示
87 0
新闻信息管理系统功能展示
|
Java 关系型数据库 MySQL
垃圾分类查询管理系统
毕业设计之垃圾分类查询,让垃圾变废为宝。
253 0
垃圾分类查询管理系统
|
监控 BI
一文看懂:商品分析如何做?
今天分享的是商品分析。在过去,商品分析曾经是最重要的分析内容,但现在已经让位给推广分析了,一起来看下吧。
292 0
一文看懂:商品分析如何做?
|
搜索推荐 数据安全/隐私保护 容器
OA系统门户是什么?全面解析信息门户的类别、难点和关键点
1.信息门户的定义 什么是门户?从传媒(类似网易、搜狐等)的角度来讲,门户是一个信息分类聚合之后的展现容器、形式,而在信息爆炸时代,门户作为一个入口的价值则是让用户在第一时间获取到他所关心以及能对他的日常工作起到帮助的信息。
4166 0