医院住院信息管理系统

医院住院信息管理系统 摘要 医院住院病区的管理包括病人出入院管理,住院病区对病人的医嘱录入、发药和计费,中心药房对药品的管理等工作,是医院管理重要一环。计算机技术在医院管理工作中应用越来广泛,住院病区管理使用计算技术实现信息传递网络化、计费电算化对提高管理水平,提高收费透明度有很现实的意义。

本文主要论述《医院住院信息管理系统》的构建过程。该系统基本实现了病人资料、办理出入院手续、医嘱录入和中心药房发药的计算机网络管理。

关键词 医院信息管理 UML 三层技术 分布式运算 Abstract This article introduces how to construct a Hospital Ward Information System with three-tiered technology. The System applies to UML, BDE, MIDAS, distributed compute theory and a special architecture to make such functions: patients check in and check out, prescription input, drug-delivery at center pharmacy and information of patient manage with computer networking. Keywords Hospital Information System, UML, three-tiered technology,distributed compute 目录 第一章 前言.............................................................................................................................1 1.1 课题的项目背景............................................................................................................1 1.2 课题的现实意义............................................................................................................1 第二章 综述.............................................................................................................................1 第三章 系统需求分析.............................................................................................................1 3.1 系统目标.......................................................................................................................1 3.2 当前系统.......................................................................................................................1 3.2.1出入院收费处……............................................................................................1 3.2.2住院病区…………............................................................................................2 3.2.3住院部中心药房……........................................................................................2 3.2.4西药库……………............................................................................................3 3.2.5问题总结…………............................................................................................3 3.3建议的系统……............................................................................................................4 3.3.1 概述…………………………………………………………….......................4 3.3.2 出入院收费处子系统………………………………………….......................4 3.3.3 病区管理子系统…………………………………………….........................12 3.3.4 中心药房子系统…………………………………………….........................15 3.3.5 西药库子系统……………………………………………….........................20 第四章 方案论证…………………………………………………………….......................24 4.1 系统架构…………………………………………………………….........................24 4.1.1客户机/服务器(C/S)体系结构基本概念………………….......................25 4.1.2两层和三层结构C/S系统的比较…………………………….......................25 4.1.2系统架构描述………………………………………………….......................27 4.2 开发工具选择….…………………………………………………….........................28 4.3 数据库平台选择….………………………………………………….........................28 4.4系统开发所使用的关键技术..……………………………………….........................30 4.4.1 Delphi的数据库访问技术…………………………………….......................30 4.4.2 Delphi5 的三层结构开发技术.……………………………......................….32 第五章 总体设计……………………………………………………………........................35 5.1 系统模块设计….…………………………………………………….........................35 5.1.1 出入院收费应用程序服务器.…………………………….....................……35 5.1.2 出入院收费系统客户端.…………………………….....................…………40 5.1.3 病区管理应用服务器.…………………………….....................……………42 5.1.4 住院病区管理客户端.…………………………….....................……………46 5.1.5 中心药房应用服务器.…………………………….....................……………48 5.1.6 中心药房客户端.………………………………….....................……………49 5.2 数据结构设计….…………………………………………………….........................50 5.2.1 系统数据库ER图.…………………………….....................……………….50 5.2.2 系统数据表结构.………………………………….....................……………51 第六章 详细设计……………………………………………………………........................59 6.1 医嘱录入..……………………………………………………………........................59 6.2产生发药记录……………………………………………………………....................62 6.3中心药房发药……………………………………………………………....................63 6.4住院费用结算……………………………………………………………....................65 6.5打印费用清单………………………………………………………………................67 第七章 测试及性能分析……………………………………………………........................68 7.1 功能测试..……………………………………………………………........................68 7.2 系统测试..……………………………………………………………........................68 7.3 性能分析..……………………………………………………………........................68 结束语..…………………………………………………………..……………........................68 致谢..…………………………………………………………………..………........................69 参考文献..………………………………………………………………..…………................69 第一章 前 言 1.1 课题的项目背景 该医院为二级甲等医院,现有门诊部和住院部,住院部设有住院病区8个,设有固定病床500张,病床使用率为80%;
医院同时还设有手术室、住院部中心药房、药库以及检验室、CT室、财务科和出入院收费处等功能辅助科室。

为了适应中国加入WTO后医疗服务市场激烈的竞争环境和上级主管部门对医院建设的需要,必须采用先进的信息技术加强对病人住院期间的费用管理,增加收费的准确性和透明度,加快处理病人入院和出院手续的速度,尽量地满足病人的需求,提高医院在医疗市场中的竞争力。同时需要完善药品管理减少药品损耗减少药品积压。

在医院的各个部门中,出入院收费处、住院病区、中心药房构成对住院病人的服务链,住院病人经出入院收费处办理入院手续后入住某住院病区接受医院的服务同时产生医疗费用,最后经出入院收费处核价收费后办理出院手续出院。住院病区是各项医疗服务的主要执行者,他与出入院收费处构成住院信息系统的两个主要部分。而在为住院病人服务的过程中,住院部中心药房根据住院部医师开出的医嘱配药,而药库则作为医院药品的采购、保管和供应部门向中心药房供应药品间接地为住院病人提供服务。因此,没有中心药房和药库子系统的加入整个住院信息管理系统是片面的,不完善的。而其他的功能辅助科室如手术室、CT室等虽然也为病人提供服务,但为减低项目的复杂程度所以暂不将这些部门纳入本项目的范围。

1.2 课题的现实意义 医院实现信息化是大势所趋,很多有经济条件的医院使用了C/S模式的医院信息管理系统。传统的两层结构C/S系统对中心服务器和网络的依赖性很大,需要投入大笔资金和大量人力和物力,而且随着业务量的增加需要不断地升级软硬件设备。这样的投入对于一些资金比较紧张的中小型医院来说是很难负担的,本课题的目标就是利用三层分布式计算技术使用较低档的计算机硬件设备实现功能上,性能上和稳定性都比较完善的医院信息管理系统。

第二章 综 述 医院信息管理系统多采用C/S模式,两层结构的C/S应用程序对网络和服务器的依赖性较大,延展性差,程序的发布也较麻烦。分布式结构出现是为了解决两层C/S结构存在的用户数量增多就导致系统效率下降和延展性差等缺点。从现在软件发展的趋势来看,采用分布式结构已经是不可避免的趋势。

目前流行的分布式系统结构分为由MicroSoft制定的COM/DCOM/COM+和由SUN、IBM等众多厂商倡导的CORBA结构。前者多用于Windows平台而后者主要用于UNIX平台,由于本系统运行于Windows平台所以采用COM/DCOM/COM+结构。

第三章 系统需求分析 3.1 系统目标 总体来说,系统的目标是提高医院住院病区的管理水平,提高医院住院费用结算的自动化水平,提高工作效率,加大住院费用的透明度。具体的目标包括:
l 加快办理病人入院、出院的速度,实现病人的医嘱和费用资料在住院的全过程自动化管理;

l 准确记录病人的各项医嘱和费用记录,实现病人费用每日清单和住院费用清单;

l 可以快速地提供准确的各项统计;

l 准确记录各种药品的购入和消耗情况,实现病区药品管理电算化和网络化;

3.2 当前系统 受到实际条件的制约,在目前情况下出入院收费处、各住院病区、中心药房和药库均使用人手操作。各部门之间通过传统的医嘱、治疗单来传递信息,不但速度慢而且容易造成差错。下面分别介绍各部门的情况。

3.2.1 出入院收费处 行政上隶属于财务科,出入院收费处担负的工作包括:为病人办理入院手续、最终核对住院费用,收取各项住院费用,为病人办理出院手续,为财务科提供财务收入数据,既是为病人提供服务的第一个环节,也是最后一环节,住院费用计算的准确性直接影响医院的经济收入和医院的声誉。出入院收费处的特点有:
(1)入院病人的住院号要正确:住院号为住院病人的唯一标识,关系到后续的各项病历、医疗收费和医疗统计的正确性。出入院处需要在办理入院时安排病人的住院号,新入院的为新号,重入院的安排上一次住院的住院号。

(2)病人住院费用结算的要求多样化:病人的住院费用除了在出院时一次结清外,住院时间长的病人费用一般会在住院期间作中途结算,但这些中途结算的时间范围是根据病人的要求确定的,情况往往是出入院算好了某一段时间的住院费用后病人家属只要求结算其中某一段时间的费用,余下费用留作下次结算再交。因此,出入院收费处需要记录每一位病人的费用及收费情况。

(3)出入院收费处是根据病区的医嘱计算病人费用的,他并不知道医嘱的实际执行情况,在一些特殊情况下往往造成多收漏收病人费用的情况。

(4)按照上级的要求,医院需要为住院病人列出住院费用明细清单。

(5)在未与社保网络联网的情况下还需要计算参加社保的病人的住院费用中社保支付部分和个人自负部分的金额。

(6)病人办理入院或出院往往集中在某一天的某一时刻,在高峰期往往会造成办理出入院手续的人积压在出入院收费处,使办理出入院手续的时间延长。

3.2.2 住院病区 住院病区的主要责任是对病人各项治疗工作的执行。由住院医师开出医嘱后由护士核对后执行具体的治疗和护理,并作相应的治疗记录。对病人的治疗主要包括:口服药物、各项点滴和注射、检查、化验、手术和其他治疗。口服药物和注射治疗所需要的药物由中心药房提供,由住院病区负责执行;
检查、化验、手术及部分的治疗项目由其他功能科室执行,住院病区负责开出治疗单。以上的各种治疗除了治疗项目本身的收费外还有另外的材料或附加收费,如药物注射除了药物本身的收费外还有注射费,部分血液化验项目除了化验项目的费用外还有抽血的费用,这些费用是跟随项目费用一起收取的。

医嘱的主要内容包括:执行时间、治疗项目名称、规格、单位、剂量、次数、开出医嘱的医师姓名、核对和执行医嘱的护士签名。

病人的医嘱分为长期医嘱和临时医嘱两种。

长期医嘱是指那些需要每天都执行的医嘱,与临时医嘱的主要区别是长期医嘱除了医嘱的开始执行时间外还有医嘱的停止时间,若没有停止时间则医嘱一直执行。长期医嘱的主要内容是各种口服或注射药物治疗,床位,诊金,护理等治疗项目。其中口服药物和注射药物需要病区护士根据长期医嘱记录到当天服药本和治疗单中,然后把服药本和治疗单送到中心药房领取药物。长期医嘱的治疗一天执行一次,早上新开出的口服药物医嘱在中午的时候送服药本到中心药房在下午就可以领到药物执行,注射或立即执行的医嘱通过治疗单可以到中心药房领药,立即执行。如果是下午新开出的长期医嘱和下午新入院病人的长期医嘱可以通过治疗单到中心药房领药,保证医嘱在下午的时候可以开始执行。

临时医嘱是指那些当天有效的医嘱,只执行一次,所以没有停止时间。临时医嘱的主要内容是药物口服或注射治疗、各种检验、化验、治疗及其他收费项目。口服和注射药物需要根据临时医嘱开出治疗单到中心药房领药,立即执行治疗。

在现在市场经济的情况下住院病区除了对病人的治疗工作外还要监测病人的费用情况,若发现费用超过其所交的住院押金则应通知病人补交押金。按照上级的要求,住院病区需要为每位住院病人打印住院费用每日清单,让病人清楚了解费用情况。

综合上面的情况可以知道,病区管理系统必须与中心药房系统联系以知道药品的发放情况和药品的规格、单位和是否缺药,也必须与出入院系统联系以了解病人的费用情况。

3.2.3 住院部中心药房 中心药房隶属于药剂科管理,负责住院病区的药品供应和指导病区正确使用药物的工作。中心药房根据病区提供的长期医嘱服药本和治疗单发药,长期医嘱服药本中记录是病区中各病人一天口服的药物,项目包括名称、规格、单位、剂量和次数,一天只发一次。治疗单中的药物为临时医嘱或需要立即执行的药物,发药的次数不限。中心药房配好药后由病区护士核对无误并在治疗单或服药本上签名后既可交由病区执行。

若遇到缺药的情况中心药房应当向药库领药,如果药库也缺药则通知住院病区缺药并更改医嘱。

3.2.4 西药库 西药库主要负责全院药物的购入、保管、发放工作。西药库按照药品公司的送货单核对药品的名称、规格、价格和数量填写药品进仓单。医院各用药部门根据需要到药库领药,药库则根据发药情况开出药品出仓单。西药库的的工作还涉及医院药品管理的其他方面,包括:
药品的价格管理,根据物价部门的指示和有关规定调整药品价格,并统计药品调价所带来的差价。

药品使用管理,对于新药要通知门诊和中心药房使用,淘汰的药品也需要通知停止使用,接近使用期限的药品要安排尽快使用,因过期、变质的药品要及时报废。

季度盘点和月度结算报表。月度结算报表主要统计药库、中心药房、西药房中各种药品的库存、进销差价率和实现差价。季度盘点报表主要是把药品的实际库存量和帐面上的库存量作比较。

西药库工作的难点在于用药部门经常需要知道某种药品在中药库是否有库存,而药库也需要及时了解用药部门的药品使用情况(存量、用量等)。

3.2.5 问题总结 由上面对住院部各部门的描述可知,现有的手工操作流程存在着下列缺陷:
l 作为核算病人住院费用的出入院收费处仅能从医生开出的医嘱计算病人住院费用,但实际的执行者是病区的护士和中心药房,出入院收费处的收费员并不了解医嘱的实际执行情况。现实操作中经常存在着医嘱漏开或医嘱开出但因为某种原因但并没有执行的情况,这样就造成了计费的不准确,使病人及家属怀疑医院医疗收费的准确性和合理性。

l 病人医嘱在病人住院期间放在住院病区,当办理病人出院或阶段结算时才交由出入院收费处核价,这个过程需要一定的时间,当病人住院时间长或医嘱比较多时尤甚。这样就造成了在办理出院的高峰期出入院收费处积压了许多病人家属等待办理出院的“壮观”场面。

l 医嘱病历没有实现电子化,无法与其他医院、其他系统实现病人资料的交换与共享。

l 作为住院部所有病区所使用的药品的供应部门,中心药房是被动地按照病区护士转抄医嘱的服药本和治疗单配药。病区的服药本和治疗单是否与医嘱相符,药品发到病区后的使用情况中心药房也不知道,也没有有效的机制保证没有执行治疗的药物及时退还给中心药房,造成病区药品管理的混乱局面。

l 负责供应药品的西药库不知道中心药房的实际库存和药品使用情况,对药品有效期的管理实际也不能做到,所以无法对医院的药品进行科学有效的管理。

l 由于人手操作的缘故,所有统计报表都由人手工计算和制作,不但效率低,容易差错,更无法作大型复杂的统计,先进的管理模式无法在医院应用,直接影响医院管理水平的提高。

出入院收费处、住院病区、中心药房、西药库因为信息彼此间不能有效沟通而形成了“信息孤岛”,是造成问题主要原因,需要在四者间建立快速的有效的信息交换通道,使数据可以自动地快速地处理和传递,减少人手操作。

3.3. 建议的系统 图3-1 系统活动图 3.3.1 概述 通过对医院住院部原有系统的了解,我们可以知道医院住院部的业务主要由财务、病区、药剂三个部门组成,传统的手工信息交换和处理手段已经不能很好地满足业务增长的需要。

因此系统改进的重点在于引入计算机网络技术和数据库技术,把各部门紧密地连接起来用计算机取代人手计算,通过网络进行信息传递取代手写传递,从而达到提高管理和服务水平,增强效率,减少差错的目的。

通过病人住院系统的活动图可以知道,住院信息管理系统由出入院收费系统、住院病区管理系统、中心药房发药系统、药库管理系统组成。系统运行的信息主要由病人资料,医嘱信息,治疗记录,费用信息,药品资料,药品使用信息,病人交费记录等信息组成,主要活动包括:办理入院手续、录入医嘱、执行治疗、计算费用、收取费用、办理出院、药品购入、药品发出等。这些信息保存在各个子系统中,分别由各系统处理,当需要信息交换时通过网络实现信息资料的共享和交换,从而实现分布式计算。

3.3.2 出入院收费处子系统 3.3.2.1系统功能需求 编号 功能 分类 R1.1 记录每一位曾经住院的病人的资料 明显的 R1.2 录入新入院病人的资料 明显的 R1.3 可以查询曾经住院的病人的资料 明显的 R1.5 根据病人的入院时间和住院病区为病人办理入院 明显的 R1.6 记录收取病人的每一笔住院押金,随时供查阅和收费结算使用 明显的 R1.7 区别已结算和未结算的住院押金 隐藏的 R1.8 显示病人现在所处的状态:未入院、等待入院、住院、阶段结算、办理出院、出院 明显的 R1.9 记录病人每次住院的资料 隐藏的 R1.10 可以修改病人的基本资料,但住院号和住院次数不能修改 隐藏的 R1.11 保证每位病人有唯一的住院号 隐藏的 R1.12 通过核对医嘱核对病人费用 明显的 R1.13 通过补充医嘱补充费用 明显的 R1.14 可以冲减病人费用记录 明显的 R1.15 不能删除或修改病区原有医嘱 隐藏的 R1.16 标记核对完成的医嘱和费用记录作为收取病人费用的依据 明显的 R1.17 显示病人的费用情况 明显的 R1.18 费用的价格按产生费用当天的价格,新生成的费用按现行价格 隐藏的 R1.19 用新补充的医嘱产生费用后如果为药品应扣减中心药房的库存 明显的 R1.20 核对完成后为病人打印交款通知单 明显的 R1.21 核对完成后应在系统中改变病人状态以便下一步操作 隐藏的 R1.22 在收款结算时可以灵活选择结算的住院押金 明显的 R1.23 根据实际的需要选择结算的费用时间阶段 明显的 R1.24 计算结算范围内的住院费用 明显的 R1.26 病人交款后打印收据 明显的 R1.27 记录每次收款的资料 明显的 R1.28 记录每次收款中现金和IC卡的金额 明显的 R1.29 保存后的收款收据可以查阅、作废和重新打印 明显的 R1.30 区别费用记录中已收款和未收款的部分 明显的 R1.31 可以按收款收据或时间范围打印费用清单 明显的 R1.32 对结算好的等待出院病人可以办理出院 明显的 R1.36 每位收款员打印缴款日报表和阶段报表 明显的 R1.37 每位收款员有独立的帐号和密码,收款员必须输入正确的帐号和密码才能操作出入院收费系统 明显的 R1.38 可以查询各医疗项目的名称、规格、单位、价格等资料 明显的 3.3.2.2 非功能性需求 用户界面和人为因素 系统的操作界面以对话框窗口为主,主要以鼠标和键盘进行操作和数据的录入。要求操作人员具有一定的windows系统的操作能力,能够阅读医嘱和基本的财务知识。

文件 系统最终以EXE可执行文件发布,另外还有操作说明书和与开发活动相关的文档 硬件 服务器要求为1G CPU,256M以上内存,40G以上的硬盘空间,要求兼容windows2000 操作系统和SQL SERVER2000数据库系统。客户端要求600MHz CPU,128M内存,20G硬盘空间,要求兼容windows98。网络连接设备要求与100M/10M以太网络技术兼容。

性能特征 要求可以同时为不少于5台客户端连接,住院病区的客户端连接不少于20台。计算一位病人的费用不多于1分钟,一般应在10秒以内。系统要尽力保证在繁忙的时间系统的响应速度。

安全 系统通过操作员帐号、密码和操作权限来保证系统不会被其他用户操作。

3.3.2.3 伪需求 数据服务器使用windows2000 操作系统和SQL SERVER2000数据库系统,客户端使用windows98操作系统,开发工具使用delphi5。

3.3.2.4 系统模型 3.3.2.4.1 用例模型 用例图3-2 用例说明 用例:
病人办理入院 参与者:
住院病人,收费员,住院管理子系统 目的:
为需要住院的病人办理入院手续,并记录下相关的住院信息 概述:
需要住院的病人到出入院收费处要求办理入院手续,收费员为病人安排住院号和住院病区,病区管理系统接收住院病人。

类型:
主要的和基本的 交叉引用:
R1.1,R1.2,R1.3,R1.4,R1.5,R1.8,R1.9,R1.10,R1.11,录入病人资料用例 典型的事件发生过程:
参与者的动作 系统响应 1. 入院病人到出入院收费处要求办理入院 2. 收费员根据姓名或住院号查找病人的资料 3. 返回病人的资料(住院号,姓名,地址等)
4.收费员根据系统返回的信息选择的操作:
a. 若没有此病人的信息应输入病人的资料 b. 若有此病人的信息应核对病人资料 5. 收费员安排住院病区和输入住院时间 6. 修改病人资料的相关属性 7. 保存入院记录 8. 住院病区管理系统接收病人 9. 设定病人为住院状态 可供选择的过程:
第4点若系统没有入院病人的信息则应录入病人的资料 若入院病人参加了社会医疗保险,则在办理入院后设定病人的社保相关属性 用例:
收取住院押金 参与者:
住院病人(发起者),收费员 目的:
记录住院病人交纳的住院押金 概述:
住院病人在办理入院后到出入院收费处交纳住院押金,收费员记录下病人所交纳的住院押金的情况。

类型:
主要的和基本的 交叉引用:
R1.6,R1.7,R1.8 典型的事件发生过程 参与者的动作 系统响应 1. 住院病人到出入院收费处交纳住院押金 2. 收费员按住院号查找病人资料 3. 返回病人的资料 4. 收费员手写一份押金收据 5. 收费员根据收据内容输入押金的信息并确认 6. 保存押金信息 可供选择的过程:
收费员还可以对输入错误的押金资料作作废处理。

用例:
计算住院费用 参与者:
住院病区管理系统(发起者),收费员 目的:
计算病人的住院费用 概述:
住院病区管理系统传送病人的医嘱和费用记录要求出入院收费处计算病人的住院费用,收费员核对病人的医嘱后指示计算费用,完成后保存病人的医嘱和住院费用。

类型:
主要的和基本的 交叉引用:
R1.12,R1.13,R1.14,R1.15,R1.16,R1.17,R1.18,R1.19,R1.20,R1.21,R1.38,核对医嘱用例,冲正费用例 典型的事件发生过程 参与者的动作 系统响应 1. 住院病区管理系统传送病人的医嘱和费用记录。

2. 系统更新病人的状态。

3. 收费员核对病人医嘱,对多收的费用应当冲正,少收的费用应当补开医嘱 4. 作相应的补发药或退药处理 5. 收费员指示计算费用 6. 计算和显示费用分类和合计 7. 收费员完成计算操作 8. 更新病人的状态,保存医嘱和费用记录,并对己计算好费用记录做标记 9. 收费员打印交款通知单给病人 用例:
费用结算 参与者:
住院病人(发起者),收费员 目的:
结算病人的住院费用 概述:
住院病人到出入院收费处要求结算住院费用,收费员根据计算好的费用记录计算好住院费用金额,收款并打印收款收据 类型:
主要的和基本的 交叉引用:
R1.22,R1.23,R1.24,R1.25,R1.26,R1.27,R1.28,R1.29,R1.30,R1.31,R1.33,R1.34,R1.35 典型的事件发生过程 参与者的动作 系统响应 1. 住院病人到出入院收费处要求结算住院费用 2. 收费员根据病人的住院号查询病人的住院费用 3. 显示并计算病人的住院费用 4. 收费员设定需要结算的住院押金 5显示未结算的住院押金 6. 收费员根据实际情况进行的操作:
a.补充病人费用 b.冲正病人费用 c.按病人要求设定结算的费用时间范围 7. 重新计算和显示病人的费用和病人应补交金额 8. 病人交款,选择有:
a. 现金交款 b. 通过IC卡交款 9. 显示费用结余情况 10. 收费员完成结算并打印收款收据 11. 保存结算信息,标识本次结算的费用记录,保存交款(现金或IC卡)和发票资料 12. 收费员可以根据病人要求打印住院费用清单 用例:
办理出院手续 参与者:
住院病区管理系统(发起者),收费员,住院病人 目的:
为住院病人办理出院手续 概述:
住院病区管理系统定义病人办理出院,收费员在病人住院费用已全部结清的情况下为住院病人办理出院手续 类型:
主要的和基本的 交叉引用:
典型的事件发生过程 参与者的动作 系统响应 1. 住院病区管理系统定义病人办理出院并传送未结算的医嘱和费用记录 2. 更新病人的状态 2. 收费员计算病人费用 3. 保存医嘱,显示并计算病人的住院费用 4. 收费员结算病人费用 5 保存结算信息 6. 办理病人出院 7. 保存病人的出院时间和出院病区,更新病人状态 用例:
录入病人资料 参与者:
收费员(发起者)
目的:
新增或修改病人的基本资料 概述:
收费员输入新的病人资料或修改已有病人的资料 类型:
主要的和基本的 交叉引用:
典型的事件发生过程 参与者的动作 系统响应 1. 收费员输入病人的住院号 2. 系统返回病人信息 3. 收费员可选择:
a.新增加一位病人 b.修改病人资料 4. 收费员保存病人资料 5. 保存病人资料,返回结果有:
a. 住院号没重复,则保存 b. 住院号有重复则要求重新输入另外的住院号 用例:
核对、录入医嘱 参与者:
收费员(发起者)
目的:
核对住院病人的医嘱,发现漏掉的医嘱应当补充 概述:
收费员把计算机记录的医嘱和实际医嘱对照,发现少录入的应当补充录入 类型:
主要的和基本的 交叉引用:
R2.3,R2.4 典型的事件发生过程 参与者的动作 系统响应 1. 收费员启动核对录入操作。输入病人的住院号。

2. 返回病人已有的医嘱,并显示已产生的费用情况。

3. 收费员发现需要增加一条新医嘱 4. 自动写入默认字段内容 5. 收费员输入执行时间和治疗项目代码 6. 返回项目信息,包括:名称、规格、单位、价格等 7. 根据返回情况系统可选择:
a. 若药品库存为缺药则要求重新输入 b. 若没有此治疗项目则要求重新输入代码 8. 收费员输入剂量、次数、用法 9. 若用法有附加治疗项目则自动增加附加项目 10. 若是长期医嘱则还应输入停止时间 11. 收费员指示保存医嘱 12. 保存医嘱 用例:
费用冲正 参与者:
收费员 目的:
冲正因医嘱错误录入等原因造成的多收病人的费用 概述:
收费员找出需要冲正费用的医嘱,然后输入冲正的数量和价格,产生冲正记录 类型:
主要的和基本的 交叉引用:
典型的事件发生过程 参与者的动作 系统响应 1. 收费员按病人的住院号、住院次数查找病人未结算的医嘱 2. 返回病人的医嘱 3. 收费员选择要冲正的医嘱 4. 计算并显示医嘱所产生的费用情况 5. 收费员输入冲正的数量和价格 5 重新计算并显示冲正后的费用情况 6. 收费员确认冲正操作 7. 保存冲正记录并作退药处理 3.3.2.4.2 出入院收费子系统类图:
图3-3 出入院系统类图 3.3.2.4.3 动态模型 图3-4核对费用顺序图 图3-5结算费用顺序图 图3-6收取住院押金顺序图 3.3.3 病区管理子系统 3.3.3.1 功能性需求 编号 功能 分类 R2.1 从出入院子系统接收等待入院的病人。

明显的 R2.2 保存本病区当前收住病人的医嘱和费用资料 明显的 R2.3 住院病区的操作员录入病人的长期医嘱和临时医嘱,并根据这些医嘱的用法生成附加医嘱项目 明显的 R2.4 录入的医嘱必须经过确认之后才能产生执行记录 明显的 R2.5 产生发药记录由住院病区的操作员驱动,长期医嘱每天发药一次,临时医嘱次数不限 明显的 R2.6 药物治疗项目的执行记录发往中心药房子系统,其他项目在系统内保存 隐藏的 R2.7 中心药房标示为缺药的药品不能发药和录入医嘱 明显的 R2.8 保存中心药房发回的发药记录作为治疗记录 隐藏的 R2.9 根据治疗记录产生住院费用 明显的 R2.10 位每位在院病人打印每日费用清单 明显的 R2.11 显示病人的费用情况、交费和住院押金情况 明显的 R2.12 定义病人为出院或阶段结算 明显的 R2.13 为出入院处提供病人的医嘱及费用记录 明显的 R2.14 为病人办理转科手续 明显的 R2.15 区别病人每次结算的医嘱和费用 隐藏的 R2.16 清理出院病人的医嘱和费用记录,保持系统运行速度 明显的 3.3.3.2 非功能性需求 用户界面和人为因素 系统的操作界面以对话框窗口为主,主要以鼠标和键盘进行操作和数据的录入。要求操作人员具有一定的windows系统的操作能力,能够阅读医嘱和基本的财务知识。

文件 系统最终以EXE可执行文件发布,另外还有操作说明书和与开发活动相关的文档 硬件 服务器要求为1G CPU,256M以上内存,40G以上的硬盘空间,要求兼容windows2000 操作系统和SQL SERVER2000数据库系统。客户端要求600MHz CPU,128M内存,20G硬盘空间,要求兼容windows98。网络连接设备要求与100M/10M以太网络技术兼容。

性能特征 要求在最系统最繁忙的时间操作基本保持流畅,住院病区的客户端连接不少于20台。打开一位病人的医嘱不多于2秒,整个病区做发药处理不多于1分钟。

安全 系统通过操作员帐号、密码和操作权限来保证系统不会被其他用户操作。

3.3.3.3 伪需求 数据服务器使用windows2000 操作系统和SQL SERVER2000数据库系统,客户端使用windows98操作系统,开发工具使用delphi5。

3.3.3.4 系统模型 3.3.3.4.1 用例模型 图3-7病区管理用例图 用例说明:
用例:
接收病人入院 参与者:
住院病区护士(发起者),出入院收费系统 目的:
接收已在出入院收费系统办理好入院手续的病人 概述:
出入院收费系统办理病人入院后由住院病区护士在病区管理系统中接收病人的信息,住院押金信息和费用信息,并通知住院收费系统病人已经入院。

类型:
主要的和基本的 交叉引用:
R2.1,R2.2 典型的事件发生过程 参与者的动作 系统响应 1. 住院病区的护士查询本病区等待入院的病人和空病床 2. 返回本病区空病床、等待入院的病人和本科医生的列表 3. 可选操作,若空病床不够可以增加病床 4. 护士选择要接收的病人、床位和主管医生 5. 护士确认操作 6. 从出入院收费系统接收病人的信息,住院押金信息和费用信息,更改出入院收费系统中病人的状态为住院 用例:
医嘱录入 参与者:
住院病区护士(发起者)
目的:
把住院医生开出的医嘱录入到计算机中保存,为产生费用记录提供依据 概述:
住院病区护士把医生开出的医嘱录入到计算机中,核对和确认后作为产生发药记录的依据。

类型:
主要的和基本的 交叉引用:
R2.3,R2.4 典型的事件发生过程 参与者的动作 系统响应 1. 住院病区护士启动录入操作。输入病人的住院号。

2. 返回病人已有的医嘱,并显示已产生的费用情况。

3. 护士增加一条新医嘱 4. 自动写入默认字段内容 5. 护士输入执行时间和治疗项目代码 6. 返回项目信息,包括:名称、规格、单位、价格等 7. 根据返回情况系统可选择:
a. 若药品库存为缺药则要求重新输入 b. 若没有此治疗项目则要求重新输入代码 8. 护士输入剂量、次数、用法 9. 若用法有附加治疗项目则自动增加附加项目 10. 若是长期医嘱则还应输入停止时间 11. 护士指示保存医嘱 12. 保存医嘱 用例:
发药 参与者:
住院病区护士(发起者),中心药房发药系统 目的:
把经过病区护士核对确认后的医嘱产生可用于计算住院费用的治疗记录 概述:
住院病区护士指示病区管理系统扫描保存的医嘱产生要求中心药房发药的信息。

类型:
主要的和基本的 交叉引用:
R2.3,R2.4 典型的事件发生过程 参与者的动作 系统响应 1. 住院病区护士指示发药 2. 返回未发药的医嘱 3. 扫描医嘱,根据医嘱的类型和内容产生请求发药信息。系统根据治疗项目的情况选择的操作有:
a. 若项目不缺药和需要执行则产生发药信息 b. 若缺药则提示停止医嘱 c. 若不需要执行则不产生发药信息 4. 向中心药房管理系统传送请求发药信息 5. 为已产生发药信息的医嘱作发药标记,防止一天内多次产生发药信息。

6. 中心药房系统发送消息发药成功 7. 接收发药信息 用例:
产生费用 参与者:
住院病区护士(发起者)
目的:
利用发药信息和其他治疗记录产生费用记录 概述:
住院病区护士指示或病区管理系统自动扫描的发药记录产生费用记录 类型:
主要的和基本的 交叉引用:
R2.3,R2.4 典型的事件发生过程 参与者的动作 系统响应 1. 住院病区护士或系统自动指示产生费用 2. 返回当天的发药记录 3. 扫描记录,产生费用记录 4. 扫描发药记录,产生附加费用记录 5. 保存费用记录 用例:
办理出院 参与者:
住院病区护士(发起者),出入院收费系统 目的:
为需要出院的病人办理出院 概述:
住院病区护士定义病人出院时间并向出入院传送医嘱和费用记录,等待出入院为病人办理出院手续,出入院收费处办理好出院手续后由病区护士清空床位。

类型:
主要的和基本的 交叉引用:
R2.12,R2.13,R2.15,R2.16 典型的事件发生过程 参与者的动作 系统响应 1. 住院病区护士输入出院病人的住院号和出院时间 2. 停止病人的全部长期医嘱 3. 向出入院收费处传送医嘱和费用记录 4. 出入院收费处为病人计算住院费用和结算 5. 出入院收费处办理病人出院 5. 保存费用记录 6. 住院病区护士清空病床 7. 修改病人和病床的信息。

3.3.3.4.2 病区管理子系统类图:
图3-8病区管理子系统类图 3.3.3.4.3 动态模型:
图3-9病区发药顺序图 3.3.4 中心药房子系统 3.3.4.1 功能性需求 编号 功能 分类 R3.1 记录每种药品的库存量 明显的 R3.2 根据各病区传送过来的治疗记录产生发药记录,并扣减库存 明显的 R3.3 对每种药品设定保证库存量,对库存不足的药品应提示需要领药并生成领药申请 明显的 R3.4 可以把发药记录按科室打印出来,方便病区核对 明显的 R3.5 保存发药记录备查 明显的 R3.6 提示病区缺药 明显的 R3.7 自动接收并保存西药库的发药信息 明显的 R3.8 手工输入西药库的出仓单 明显的 R3.9 根据输入药品的盘点数量生成盘点报表 明显的 R3.10 根据盘点数量校正药品库存量 明显的 R3.11 药库的发药信息经确认后增加药品库存 明显的 3.3.4.2 非功能性需求 用户界面和人为因素 系统的操作界面以对话框窗口为主,主要以鼠标和键盘进行操作和数据的录入。要求操作人员具有一定的windows系统的操作能力,能够阅读医嘱和基本的财务知识。

文件 系统最终以EXE可执行文件发布,另外还有操作说明书和与开发活动相关的文档 硬件 服务器要求为1G CPU,256M以上内存,40G以上的硬盘空间,要求兼容windows2000 操作系统和SQL SERVER2000数据库系统。客户端要求600MHz CPU,128M内存,20G硬盘空间,要求兼容windows98。网络连接设备要求与100M/10M以太网络技术兼容。每台工作站配备窄行打印机一台。

性能特征 要求在最系统最繁忙的时间操作基本保持流畅,中心药房的客户端连接不少于4台。当接收到病区传送的发药信息时能够立即提示配药人员。

安全 系统通过操作员帐号、密码和操作权限来保证系统不会被其他用户操作。

3.3.4.3 伪需求 数据服务器使用windows2000 操作系统和SQL SERVER2000数据库系统,客户端使用windows98操作系统,开发工具使用delphi5。

3.3.4.4 系统模型 3.3.4.4.1 用例模型 图3-10 中心药房系统用例图 用例说明:
用例:
领药 参与者:
中心药房主管(发起者),药库管理系统 目的:
到药库领取药品,增加中心药房的药品库存 概述:
中心药房主管提出领药请求,药库管理系统根据领药请求发药并开出药品出仓单,中心药房主管核对出仓单和药品后确认领药,中心药房增加药品的库存。

类型:
主要的和基本的 交叉引用:
R3.1,R3.3,R3.7,R3.8,R3.6 典型的事件发生过程 参与者的动作 系统响应 1. 中心药房主管查询系统记录的领药需求 2. 返回领药需求记录 3. 中心药房主管修改系统记录的领药需求 4. 保存领药需求记录 5. 中心药房主管以打印或发送数据的形式向药库管理系统发送领药请求。

6. 药库管理系统接收发药请求 7. 药库管理系统发药,传送发药信息或由中心药房主管输入出仓单。

8. 接收并保存发药信息 9. 中心药房主管确认药库发药信息 10. 增加药品库存量 11. 若需要提示病区缺药则向病区管理系统发送缺药信息 12. 向病区系统发送缺药信息。

用例:
发药 参与者:
病区管理系统(发起者),配药员 目的:
根据病区管理系统发送的发药请求配药,相应减少药品库存量并把发药信息发送回病区管理系统。

概述:
病区管理系统向系统发送发药请求,配药员查看这些发药请求配药,确认后系统扣减药品库存,并向病区管理系统回传发药信息,系统打印配药单以方便核对。

类型:
主要的和基本的 交叉引用:
R3.2,R3.3,R3.4,R3.5 典型的事件发生过程 参与者的动作 系统响应 1. 病区管理系统传送请求发药信息 2. 保存请求发药信息 3. 配药员查阅请求发药信息 4. 保存请求发药信息 5. 配药员确认发药 6. 扣减药品库存并生成发药记录 若缺药则系统查询药库管理系统药库是否有库存,有则产生领药信息,没有则提示病区管理系统缺药。

7. 系统根据药品库存情况可选择 a. 库存大于库存下限则不作处理 b. 库存小于库存下限则生成领药信息 8. 配药员打印发药单 10. 病区管理系统接收发药信息 3.3.4.4.2 中心药房发药子系统类图 图3-11 中心药房发药子系统类图 3.3.4.4.3 动态模型:
图3-12药房发药顺序图 3.3.5 西药库子系统 3.3.5.1 功能性需求 编号 功能 分类 R4.1 保存每笔药品进仓记录,并增加库存 明显的 R4.2 保存每笔药品出仓记录,并减少库存 明显的 R4.3 产生和保存进仓单 明显的 R4.4 产生和保存出仓单 明显的 R4.5 根据药品供应商的发票选择结算的进仓记录 明显的 R4.6 保存每次结算的数据 明显的 R4.7 药品进仓时登记药品的批号和有效期,并增加这药品的库存 明显的 R4.8 药品出仓时由仓管员选择发出的批号,并减少药品的库存 明显的 R4.11 根据输入药品的盘点数量生成盘点报表 明显的 R4.12 根据盘点数量校正药品库存量 明显的 R4.13 对每种药品设定保证库存量,对库存不足的药品应提示需要领药并生成采购计划 明显的 R4.14 接收用药部门的领药申请 明显的 R4.15 根据领药申请自动生成出库单,并扣减库存 明显的 R4.16 对药品进行价格调整,并通知用药部门跟随调整价格 明显的 R4.17 统计药品价格调整带来的差额 明显的 R4.18 录入、保存、修改药品信息 明显的 3.3.5.2 非功能性需求 用户界面和人为因素 系统的操作界面以对话框窗口为主,主要以鼠标和键盘进行操作和数据的录入。要求操作人员具有一定的windows系统的操作能力,能够熟悉药库的日常管理运作。

文件 系统最终以EXE可执行文件发布,另外还有操作说明书和与开发活动相关的文档 硬件 服务器要求为1G CPU,256M以上内存,40G以上的硬盘空间,要求兼容windows2000 操作系统和SQL SERVER2000数据库系统。客户端要求600MHz CPU,128M内存,20G硬盘空间,要求兼容windows98。网络连接设备要求与100M/10M以太网络技术兼容。每台工作站配备窄行打印机一台。

性能特征 要求在最系统最繁忙的时间操作基本保持流畅,中心药房的客户端连接不少于4台。当接收到病区传送的发药信息时能够立即提示配药人员。

安全 系统通过操作员帐号、密码和操作权限来保证系统不会被其他用户操作。

3.3.5.3 伪需求 数据服务器使用windows2000 操作系统和SQL SERVER2000数据库系统,客户端使用windows98操作系统,开发工具使用delphi5。

3.3.5.4 系统模型 3.3.5.4.1 用例模型 图3-13药库管理系统用例图 用例说明:
用例:
药品进仓 参与者:
药品供应商(发起者),仓管员 目的:
登记药品入库 概述:
药品供应商向仓管员提供入库药品的随货同行联,仓管员根据随货同行核对药品的品种、产地、规格、数量后把资料输入到计算机中并打印药品入库单。

类型:
主要的和基本的 交叉引用:
R4.1,R4.3,R4.7,R4.18 典型的事件发生过程 参与者的动作 系统响应 1. 药品供应商提供随货同行 2. 仓管员输入供应商的代码 3. 显示供应商的资料 4. 仓管员生成进仓单 5. 生成一张进仓单,并写入进仓单的资料 6. 仓管员输入一条药品进仓信息,包括:单据号,编码,数量,批号,产地,进货价 7. 仓管员提示确认输入 8. 保存进仓单内容并相应增加药品的库存 8. 仓管员打印进仓单 用例:
购药货款结算 参与者:
药品供应商(发起者),药品会计 目的:
结算购药货款 概述:
药品供应商向药品会计提供入库药品的发票联要求结算购药款,药品会计根据药品进仓记录与发票联核对后结算货款,其余未结算的进仓记录留作以后结算。

类型:
主要的和基本的 交叉引用:
R4.5,R4.6 典型的事件发生过程 参与者的动作 系统响应 1. 药品供应商提供发票联 2. 药品会计查询供应商的供药记录 3. 显示该供应商的药品进仓资料 4. 药品会计核对发票和进仓记录并标记要结算的进仓记录 5. 计算货款的总额 6. 药品会计指示完成结算 8. 保存结算的信息 用例:
发药 参与者:
中心药房管理系统(发起者),仓管员 目的:
为中心药房发药 概述:
中心药房向药库提出领药要求,仓管员根据这些要求和药品库存情况发药给中心药房,开出出仓单和发送发药信息。

类型:
主要的和基本的 交叉引用:
R4.2,R4.4,R4.13,R4.14,R4.15 典型的事件发生过程 参与者的动作 系统响应 1. 中心药房系统传送请求领药信息或打印领药申请单 2. 显示申请领药信息 3. 仓管员指示生成出仓单 4. 生成一张出仓单 5. 仓管员输入发出药品的代号和数量 6. 仓管员确认输入 7. 保存保存出仓记录并发出发药信息 8. 中心药房系统确认发药 9. 扣减库存量 用例:
盘点 参与者:
药品供应商(发起者),药品会计 目的:
结算购药货款 概述:
药品供应商向药品会计提供入库药品的发票联要求结算购药款,药品会计根据药品进仓记录与发票联核对后结算货款,其余未结算的进仓记录留作以后结算。

类型:
主要的和基本的 交叉引用:
R4.5,R4.6 典型的事件发生过程 参与者的动作 系统响应 1. 药品供应商提供发票联 2. 药品会计查询供应商的供药记录 3. 显示该供应商的药品进仓资料 4. 药品会计核对发票和进仓记录并标记要结算的进仓记录 5. 计算货款的总额 6. 药品会计指示完成结算 8. 保存结算的信息 用例:
药价调整 参与者:
药品供应商(发起者),药品会计 目的:
结算购药货款 概述:
药品供应商向药品会计提供入库药品的发票联要求结算购药款,药品会计根据药品进仓记录与发票联核对后结算货款,其余未结算的进仓记录留作以后结算。

类型:
主要的和基本的 交叉引用:
R4.5,R4.6 典型的事件发生过程 参与者的动作 系统响应 1. 药品供应商提供发票联 2. 药品会计查询供应商的供药记录 3. 显示该供应商的药品进仓资料 4. 药品会计核对发票和进仓记录并标记要结算的进仓记录 5. 计算货款的总额 6. 药品会计指示完成结算 8. 保存结算的信息 3.3.5.4.2 药房管理系统类图:
第四章 方案论证 医院的信息化建设需要投入大量的人力和财力,一个完备的医院信息系统往往由中心服务器、数据通讯网络,数据库平台,客户端计算机以及客户端应用程序构成。一些规模较大的医院可以投入数以百万计的资金,构建功能完备、可靠性高的系统。这些系统往往以小型机作为中心服务器,以光纤作为主干,并且使用昂贵的网络设备。对于很多中小型医院来说她们是很难负担这笔费用的,她们可能负担配置较低比较简单的系统。对于一家需要建立现代化管理的医院来说,不论她的规模大小功能需求其实是一样的,不同的只是数据的处理量多寡而已。

传统的信息处理系统数据处理多由服务器完成,数据通过网络传输,对服务器和网络的要求较高,系统投入使用后随着业务量、储存数据和客户端连接数量的不断增加系统的负荷会越来越大,当这种负荷达到一定程度的时候就会造成系统运行的不稳定和性能下降,这又需要投入一大笔资金升级系统了。

本课题的研究思路就是要利用价格相对低廉的设备构建系统,尽量地减少服务器和网络的负荷,使业务量的增加不会对整个系统的负荷有太大地影响。

4.1 系统架构 在讨论医院信息系统的架构之前,首先回顾一下计算机网络发展的过程。计算机网络主要经历了以下几个发展阶段:
主机/终端(Mainframe/Terminal)模式;

文件服务器/工作站(FileServer/Workstation)模式;

客户机/服务器(Client/Server)模式;

浏览器/服务器(Browser/Server)模式。

从应用软件的角度来看,客户机/服务器网络模式下的软件结构简称为C/S结构,浏览器/服务器网络模式下的软件结构简称为B/S结构。现在C/S结构和B/S结构得到了广泛的应用,主机/终端(Mainframe/Terminal)模式和文件服务器/工作站(FileServer/Workstation)模式在新构建的系统中已很少使用。

Client/Server(C/S)是当前数据库应用程序中极为流行的一种方式,尤其是网络技术的充分发展后,当前很多系统都采用这种方式进行构造,其最大优点是将计算机工作任务分别由客户端和服务器端来共同完成,这样有利于充分合理利用系统资源。而我们经常提到的Browser/server(B/S)结构,它也是采用C/S结构的基本思想,使用浏览器作为系统前端,实现了我们理想中的瘦客户。但是系统的工作量并没有真正减少,而是将部分客户端的工作量交付给服务器端来完成。考虑到技术风险的问题,本系统采用的是C/S结构。

4.1.1客户机/服务器(C/S)体系结构基本概念 典型的客户机/服务器包括一个客户机(或称前端),一个服务器(或称后端),客户机的作用是访问和处理远程服务器上的数据,服务器的作用是接收和处理客户机的数据请求。有时,可能有多个客户向同一个服务器同时请求服务,这就需要服务器决定怎样处理这些请求。因此,在许多客户机/服务器结构中,除了客户机和服务器外,也可以还有其它部分,通常讲的三层客户机/服务器结构中的中间层。

4.1.1.1 企业逻辑 企业逻辑就是系统处理和访问数据的定义、属性、行为、关系、法则、政策和限制。企业逻辑是整个系统的核心,决定了整个系统的数据是如何组织、处理和保存的,没有了企业逻辑系统的数据只是一堆无序的数据而已。在医院信息管理系统中,典型的企业逻辑有:
病人资料的录入、保存和管理规则;

病人办理出入院手续的流程;

医嘱录入规则;

病人医嘱产生治疗记录规则;

中心药房发药制度;

费用生成规则;

病人费用管理制度,等。

这些企业逻辑的设计依据来源于需求分析中对系统功能需求和约束的定义和系统模型。在面向对象的分布式处理概念中,企业逻辑由不同的功能对象实现。这些对象包括了专门存取数据的数据对象(Data Object),代表实际世界中实体事物的实体对象(Entity Object),负责企业功能的企业法则对象(Business Rule Object)等对象。这些不同的功能对象都统称为企业对象(Business Object)。

4.1.1.2客户机 客户机(Client)是指请求服务的计算机,既可以是微型机、小型机,也可以是大型机,它具有向服务器发送服务请求和显示相关数据的所有功能。客户机上的软件至少包括两类:能访问服务器数据的应用程序和网络接口软件。应用程序用于向服务器发送服务请求和显示相关数据;
网络接口软件可提供各种数据传输协议。没有或很少实现企业逻辑的客户机被称为瘦客户(ThinClient)。当然,客户并非完全没有处理企业逻辑的能力,相反,也可以把部分或全部企业逻辑设计在客户机中,使其可以承担一定的数据处理能力,这样的客户就叫胖客户(flatclient)。

4.1.1.3 服务器 服务器(Server)是指提供服务的计算机,它能够等待客户的请求然后处理这些请求。一个服务器必须能够根据企业逻辑处理来自多个客户的多个请求。服务器上的软件至少包括两类:能处理客户机请求的应用程序和网络接口软件。在传统的两层结构的C/S系统中,企业逻辑由数据库平台的存储过程、触发器、视图以及完整性约束完成。

在三层结构的C/S系统中,服务器可分为专门负责数据储存的数据服务器和运行企业逻辑的中间层应用服务器组成。

4.1.2 两层和三层结构C/S系统的比较 两层C/S结构就是客户端应用程序通过ODBC、SQL Link、TCP/IP直接连接数据库服务器进行通信,并完成数据的添加、修改、删除和检索等操作。从系统结构图和以往开发的经验看,两层C/S结构存在以下缺点:
(1)在两层C/S结构中,客户端应用程序直接连接数据库服务器,这样数据库服务器将消耗一定的资源以处理与客户端的连接工作,并以并行方式处理客户端的处理要求。当连接的客户端达到一定数量时,数据库服务器的运行效率将会不断下降;

(2)在两层C/S结构中,只有唯一一个在线的数据库服务器,这种结构将成为系统可靠性的重大隐患。如果数据库服务器因为某种原因而停止工作,那么整个系统将趋于瘫痪。

(3)两层C/S结构应用程序的分发比较麻烦,需要一些*.d11支持。以DELPHI为例,客户端需要安装几个BDE .dll文件,另外每个客户端还需要配置ODBC或BDE。

(4)采用瘦客户模式的C/S系统由于处理都集中在服务器,系统中其他计算机很多时候处于空闲状态,他们的CPU资源和存储空间没有得到有效利用,系统升级服务器后原有数据库服务器无法再利用,造成资源和投资的浪费。如果使用胖客户模式虽然可以利用系统中客户机的资源,减少数据库库服务器的负荷,但由于企业逻辑存在于每台客户机中,若要更新程序或修改企业逻辑则要所有客户端程序都要更新,若系统中客户端计算机分布广泛或数量众多,会给维护工作带来很大的不便。

正是由于两层C/S结构存在上述缺点和不足,使得自从C/S结构问世之日起,研究人员就不断致力于改进和完善它。对于上述存在的问题,解决的方法就是在客户端和数据库服务器之间加入一个企业逻辑(Business Logic)层,该层通常存放在另一台被称为应用服务器(Application Server)的机器上。三层C/S逻辑结构如图4-1所示。

图4-1 新加入的企业逻辑层负责对企业逻辑的执行工作和对数据服务器的连接工作,它一方面接收客户端的处理请求并转送给数据库服务器,另一方面将数据服务器的查询结果经处理后返回送给客户端。数据库服务器只需要专心响应应用服务器的数据访问请求,一方面减少了连接数量,另一方面不再负责企业逻辑的执行工作,这样就大幅度减轻了数据库服务器的工作负担,加快了其响应速度。使系统的整体工作效率也得到提高。若把企业逻辑按照功能划分为几个子模块,分别置于几个应用服务器中,从而实现企业逻辑的分布式计算,这样不但可以提高系统的响应速度,而且可以充分利用系统中配置较高的计算机的处理能力。

另外,应用服务器还提供了负载平衡、容错处理Database Pooling(连接池),Object Pooling(对象池)等技术,最大限度地增加对系统资源的利用程度。()ng t Pooooling, 综上所述,采用三层C/S结构具有以下优点:
(1)提高系统的安全性。三层C/S结构将数据连接放在应用服务器上,而不像两层结构将数据连接放在客户端,这样在很大程度上提高了数据库服务器的安全性。

(2)网络负载平衡。当有许多客户端应用程序需要连接到应用程序服务器的时候,MIDAS能够分配不同的客户端应用程序到每一个应用服务器中,以平均每一个应用程序的负荷。

(3)容错处理。当系统中某一应用程序服务器发生故障时,客户端应用程序能够自动寻找另外的应用程序服务器以维持自己的运作。同时客户端应用程序还可以把编辑的数据以文件的形式保存到磁盘中。

(4)分发简单。客户端应用程序只须MIDAS.d11支持。如果需要更改企业逻辑的话只需要更新应用服务器程序就可以了。

(5)实现分布式计算,一方面可以充分利用系统中的计算机资源,另一方面可以减少因为故障引起的系统功能的丧失。

结合到医院信息管理系统的实际情况,采用三层结构,使用数台比较高档的PC作为数据服务器和应用服务完全可以建立一个功能比较完善和可靠的医院信息管理系统。

4.1.3 系统架构描述 按照需求规格说明书的描述,把医院住院信息管理系统分成出入院收费系统、住院病区管理系统、中心药房发药系统等三个功能相对独立的子系统。各子系统均有各自的数据服务器、应用服务器和客户端,可以实现各自的独立运行和操作,各子系统之间通过特定的接口彼此交换数据。系统架构如图4-2所示:
整个系统可以在一台机器上实现也可以把数据服务器、应用服务器和客户端放在不同的计算机上实现。出入院收费系统、中心药房发药系统各自由一台数据服务器和应用服务器加上若干客户端组成。但住院病区管理系统则可以有所不同,每组数据服务器和应用服务器可以为一到若干个住院病区服务,这些病区可以是地理位置相对靠近(如同一楼层或同一栋楼),也由系统管理人员根据病区的处理负荷灵活配置,比如病床数多的病区可以单独安排一组数据服务器和应用服务器,数个病床较少的病区可以共用一组数据服务器和应用服务器。客户端可以根据需要连接到不同的应用服务器上。

这样的架构给系统的构建带来了很大的灵活性,根据病区本病区的医嘱一般不会拿到另一病区的计算机上录入的实际情况,如果该病区的住院病区管理系统的数据服务器、应用服务器和客户端均在一台计算机上实现,那么该病区系统的大部分操作均在本机完成,只在需要发送或接收数据时才使用网络。采用这种结构的好处一是可以大大地减轻系统网络的负担,二是使得业务量增加对整个系统的影响很少,某病区服务器负荷得增加对其他病区服务器基本没有什么影响,需要升级时也只需升级负荷过重的服务器,三是某病区服务器出现故障时也只影响使用该服务器的病区,对其他病区没有影响。但是,这种结构也存在着类似“胖客户”存在的维护困难等缺点。

在三层结构下,应用服务器提供数据接口和方法接口供客户端访问和调用,应用服务器根据企业逻辑向数据服务器存取数据和处理数据,最后把结果返回给客户端。应用器器完全完全 4.2 开发工具选择 现在流行的RAD(Rapid Application Develop)工具有MicroSoft公司的Visual Basic,Visual C++,Inprise 公司的Delphi和C++ Builder,虽然这些开发工具各有特点,但从易用性,开发速度,应用程序的运行速度方面考虑Delphi无疑是当中的佼佼者。在选择开发工具时需要考虑的问题包括:
l 开发工具本身的性能。

l 稳定性和可靠性。

l 可视化开发。

l 面向对象技术。

l 提供4GL。

l 开放性。

l 团队开发能力。

l 数据库访问能力。

l 支持ODBC及其他数据库访问接口。

l 支持ADO及OLE DB。

l 支持数据库产品的扩展能力。

l 数据访问速度。

l 对不同解决方案的支持能力。

l 支持Windows DNA。

l 支持CORBA。

l 支持分布式结构。

l 技术支持和市场环境等。

Delphi是Inprise公司于1995年推出的RAD开发工具,现在版本已经升级到7.0,Delphi以Object Pascal语言为基础,加强了IDE功能和增加了VCL(可视化组件库),非常适合快速开发windows应用程序。Delphi把开发windows应用程序所要用到的代码以控件件的形式封装在VCL中,开发人员使用时只需把控件拖拉到设计窗口中然后输入属性值即可。到拉Ldows与Visual C++相比开发工作要简单很多,而且程序的运行速度相差无几;
与以以简单易用语言ect Pascal,著称的Visual Basic相比易用性毫不逊色,但由于Delphi最终产生的程序为机器码,计算机可以直接执行,运行速度比Visual Basic产生的伪代码要高很多。Delphi的优势还体现在:
面向对象的软件工程 开发基于组件的软件已成为当今软件开发的趋势。Delphi不仅可以开发出功能强大的基于VCL的组件,还支持MicroSoft的组件对象模型COM,可以轻松开发出ActiveX控件。这样通过创建、集成、组装这些组件,可以满足基于对象重用和对象分布的不同解决方案,真正实现面向对象的高效的软件开发。

多层分布式系统的开发 基于多层结构的分布式系统对C/S应用程序开发的需求不断增长。Delphi既支持MicroSoft的Windows分布式Internet应用程序体系结构Windows DNA,也支持CORBA。CORBA是由Object Management Group于90年代初开发的规范,得到IBM、SUN等众多厂商的支持,适用多种操作系统平台的网络环境。

强大的数据库编程能力 数据库编程一向是Delphi的强项。Delphi5除了使用她著名的BDE引擎外,还提供了对ActiveX数据对象ADO的支持,为数据库编程提供了更大的灵活性。另外新改进的多层分布式应用程序组件MIDAS为开发基于数据库的动态Web应用程序提供了方便。

Internet/Intranet开发 软件的分布和通讯是在Windows 环境下进行C/S应用程序开发的主要问题,Internet技术的使用能够减少这两个问题。Delphi5提供了Internet开发技术解决方案。包括:支持HTML4和XML的Internet Express,支持Web中间件和其他Internet控件的VCL等,使用户可以方便地开发出Web应用程序,创建电子商务系统。

智能开发环境 包括IDE、各种向导、调试跟踪技术等。

另外,还使用了Woll2Woll Software公司开发的InforPower2000第三方控件,这些组件是Delphi中原有的Data Access和Data Controls组件的功能增强版,使开发数据库应用程序更加方便快捷。

4.3 数据库平台的选择 数据库平台选用的是MicroSoft 公司的SQL Server 2000,SQL Server 2000是SQL Server的最新版本,比以前版本提高了性能、可靠性、质量和易用性。Microsoft SQL Server 2000 增加了几种新的功能,由此成为大规模联机事务处理 (OLTP)、数据仓库和电子商务应用程序的优秀数据库平台。SQL Server 2000拥有大型数据库系统基本特征,但保持了windows环境下界面友好,操作简单的优点,成为windows环境下开发中、小型C/S系统较流行的数据库系统。与传统的桌面数据库系统相比SQL Server 2000有以下区别:
⑴.面向集合与面向记录。面向集合与面向记录应该是C/S系统与桌面数据库系统的最本质的区别。在桌面数据库系统中,它得到的是整个数据表,面向的是整个数据表的所有记录,因此,在桌面数据库系统中,第一条;
上一条、下一条、最后一条等概念是非常普遍的,而在C/S系统中没有这些概念,因为客户程序在向服务器发送服务请求时,得到的数据可以由一个或多个数据表的多个字段构成,是服务器上所有数据的一个子集,它的请求是通过SQL语句来实现的,因此在C/S系统中,它面向的是整个数据库的一个子集合。

在C/S系统中使用TTable组件,与桌面数据库系统不同的是,通过它发出的数据库操作命令必须通过BDE转换成SQL代码,才能被数据库识别地执行。这不仅限制了对数据库的访问,而且大大降低了系统运行效率。下面举个简单事例加以说明:假设我们使用TTable组件访问一个SQL数据库,并且只从数据表中获得一条或几条记录时或者一个或几个字段时,需要首先执行“Tablel.Open;
”命令,经BDE转换成SQL语句将数据表打开,当数据很大时(数据字段很多或数据记录很多),服务器会返回一个庞大的数据集,因此,系统消耗包括网络消耗是可想而知的。

⑵.数据安全管理。SQL数据库在数据安全性管理方面比桌面数据库系统要强得多,它不仅对数据库的访问进行口令验证,而且它还能够对特定的数据库对象进行限制,包括视图、数据表的存储过程,更重要的是它可以设置用户权限,通过Grant和Revoke命令向一个用户或一组用户授权或收权。

⑶.数据完整性管理。对于SQL数据库而言,它允许在服务器端定义一些业务规则用于验证数据的完整性,强制所有的客户端程序都必须接受相同的业务规则约束,这样有利于集中维护这些规则。虽然桌面数据库系统也能进行数据完整性管理,但是它只能在应用程序中定义这些验证规则,所有需要验证的地方都必须写入相同或相似的代码,这样不利于维护这样规则。另外,SQL数据库在完整性约束上,一般在创建数据表时就定义好的,它既可以定义为数据表的一部分,也可以通过存储过程或触发器等形式从数据表中独立出来。

⑷.数据库的并发访问管理。SQL数据库采用优化锁定策略,允许多个用户可以同时访问服务器而不互相干扰。这种技术并不限制客户访问当前正在被其它用户访问的数据表,可以照常对它进行编辑(增、删、改),并请求服务器保存修改的数据。桌面数据库系统则明确地或完全地锁定策略,也就是说那些当前正在被其它用户使用的数据无法访问,更无法编辑,如果试图访问或修改这些数据,系统产生错误的提示信息。

⑸. 事务控制。用于在系统发生错误时保持数据库的一致性和完整性。每个更新 SQL Server 数据库内数据的应用程序都使用事务完成这个任务。事务是由一系列语句(选择、插入、更新或删除)构成的逻辑工作单元。如果在事务执行过程中没有遇到错误,则事务中的所有修改成为数据库的永久部分。如果遇到错误,则不对数据库做任何修改。桌面数据库系统一般不提供事务控制功能。

4.4 系统开发所使用的关键技术 4.4.1 Delphi的数据库访问技术 Delphi5可以通过BDE(Borland Database Engine)或ADO(ActiveX Data Object)访问数据库。由于本项目使用BDE访问数据,所以下面重点介绍Delphi5基于BDE的数据访问技术。

l 一个基于BDE的一层或两层结构的Delphi应用程序包括下列组件:
l 一个包含数据感知(data-aware)控件的用户界面。

l 一个或多个从物理数据表访问数据的数据集(dataset)。

l 每个数据集有一个数据源(datasource)对象连接数据集的数据感知控件。

l 可以有一个或多个数据库组件用于事务控制和连接管理。

l 可以有一个或多个会话组件用语分隔数据访问操作。

BDE的架构由下图4-3所示:
4.4.1.1.数据库和数据集 数据库包含存在数据表内的信息,它们也包含信息表用以说明在数据库中包含了哪些信息,例如数据表所用的索引对象以及SQL的存储过程对象。

组件面板的DataAccess页中包含了不同的数据集组件,它们代表了数据库中包含了数据表或者由存储在这些数据表的数据构成的逻辑数据表,必须在用程序中包含一个数据集组件以使用数据库信息。

在DataAccess页中的每一个基于BDE的数据集组件有一个公开的DatabaseName属性来指定数据库,该数据库包含有数据表或处理数据集中信息的数据表。当设置应用程序时,在将数据集绑定到数据库内特定信息之前,必须使用此属性来指定数据库,设置的值依赖于以下值。

数据库有一个BDE别名。可以为DatabaseName属性指定一个BDE别名,一个BDE别名代表一个数据库加上这个数据库的设置信息,与一别名相关联的设置信息由不同的数据库类型(Qraclc、Sybase、InterBase、Paradox、dBASE等)决定,使用BDE系统管理工具或者SQL可创建并管理BDE别名。

数据库是一个Paradox或者dBASE数据库,如果使用一个Paradox或dBASE数据库,DatabaseName的值可以设为数据库表所在的目录。

使用一个明确的数据库组件,数据库组件(TDatabase)表示了应用程序中的数据库。如果没有明确地加入一个数据库组件,可根据DatabaseName属性自动创建一个临时的数据库组件;
如果使用了明确的数据库组件,则DatabaseName的值就是该数据库组件的DatabaseName属性值。

4.4.1.2. session session(会话)隔离了数据库的数据存取操作,如数据库的连接和管理数据库群组。所有BDE的使用发生在一个session的环境中,可以使用session来指定应用于session中所有数据库的设置信息。这允许覆盖由BDE系统管理工具指定的缺省行为。

可以使用一个session来:
管理BDE别名,可以创建新的别名、删除别名以及修改已有的别名。更改缺省设置只会影响到session。但能够编写更新以使它们被永久加入到BDE的配置文件中。

在二级应用程序的数据库连接结束时进行控制。当数据库没有任一数据集动作时,保持数据库连接占用了一些会被释放的资源,这样会改善速度并减少网络流量,若要在没有数据集动作时,也保持数据库连接,KeepConnections属性应被设为true(缺省值)。

管理存取于一级应用程序中的有口令保护的Paradox及dBASE文件。当要存取有口令保护的Paradox和dBASE数据表的数据集,且必须打开这些数据表时,这些数据集需使用session组件以提供口令。可以覆盖缺省行为(不论是否需要口令,一个口令对话框会出现),而以程序提供口令。如果要把一级应用程序扩展至二级或多级应用程序,可以创建一通用的用户接口以取得用户的授权信息,而当转到使用在服务器(不是表)层次上需要用户名和口令的远程数据库服务器时,这些授权信息不用改变。

指定特定的Paradox目录所在位置,在网络上被共享的Paradox数据库使用一个存放数据表和记录锁定信息的临时文件的网络目录,Paradox数据库也使用一个存放查询结果临时文件的私有目录。

如果应用程序需要同时多次存取同一个数据库,则必须使用多个session来隔离数据库的这些使用。否则,将扰乱那个数据库上管理事务的逻辑(包括那些自动性的事务)。当执行多个查询或使用多个线程时,应用程序会有同步存取的危险。

除非需要使用多个session,否则可以使用缺省的session。

4.4.1.3 数据库连接 BDE包括可与不同数据库连接的驱动程序,Delphi标准版包括本地数据库的驱动程序:Paradox、dBASE、FoxPro和Access。ODBC适配器允许BDE使用ODBC驱动程序,通过支持ODBC驱动程序,应用程序能够使用任何ODBC兼容的数据库,Delphi企业版也包括对远程数据库服务器的驱动程序,使用SQLLinks安装的驱动程序可以与远程数据库服务器(如InterBase、Oracle、Sybase、Informix、MicrosoftSQL服务器和DB2)进行联系。

基于BDE的一级应用程序与基于BDE的二级应用程序唯一的区别在于:是使用本地数据库还是使用远程数据库服务器。

4.4.1.4 使用事务 一个事务是作用于一个数据库的一个或多个数据表的一组动作,这组动作在被确认(永久有效)前必须全部成功执行,如果动作之一失败了,则所有动作将被恢复(未做)。使用事务,可以确保当事务内的某一动作发生问题时,数据库不会停留在不一致的状态下。

例如,在一个银行应用程序中,将金额从一个帐户转到另一帐户就是一个需要利用事务来保护的动作。如果当一个帐户的金额减少时,另一个帐户的余额增加时发生了错误,这时要恢复事务以使数据库内仍然有正确的总余额。

缺省时,BDE为应用程序提供了隐含事务控制。当一个应用程序在隐含事务控制之下时,另一个独立的事务会被用于数据集中每一个要被写人数据库的记录。隐含事务能同时保证最少的记录更新冲突及一致的数据库视图。另一方面,因为要被写入数据库的每一行数据都发生于自己的事务内,隐含事务控制可能导致过多的网络传输量和较低的程序效率。同时,隐含事务控制不会保护多个记录的逻辑操作,如前述的金额转帐。

如果显式控制事务,可以选择最有效的时间来启动、确认及恢复事务。当在多用环境中开发应用程序时,尤其是当应用程序与一个远程SQL服务器对比工作时,应该显式控制事务。可以利用缓存更新的方法使所需的事务次数降到最低。

4.4.1.5 缓存更新 DE对缓存更新提供支持。当进行缓存更新时,应用程序从数据库接收数据,在本地做所有的修改并暂存数据,然后缓存更新到数据集。缓存更新在单一事务中被应用到数据库。

缓存更新能够降低事务次数,减少网络流量。不管如何,缓存的数据是在应用程序的本地并且不受事务的控制,这就意味着当使用本地及内存中的数据时,其他应用程序也能改变数据表内的数据;
它们也不能看到所做的任何改变,直到进行缓存更新为止。因此,缓存更新对使用易变的数据的应用程序是不适合的,因为当想要将更新合并至数据库时,会产生或遇到过多的冲突。

可以使用CachedUpdates属性来告诉基于BDE的数据集进行缓存更新。当更新完成时,它们可以通过数据集组件、数据库组件、或者某个特定的更新对象来进行。当没有另外的处理(如:使用一个联合查询时)过程,更新不能被作用于数据库时,必须使用OnUpdateRecord事件对每一个由联合视窗(joinedview)构成的数据表执行更新。

4.4.2 Delphi5 的三层结构开发技术 4.4.2.1 三层应用系统结构 一个三层C/S应用程序被分离到运行在不同机器上的逻辑单元。三层应用程序通过局域网或Internet通讯和交换数据,他们具备集中的企业逻辑、分布式数据处理和瘦客户端等优点。一个三层应用程序包括下列三个部分:
l 客户端应用程序:在用户的计算机上提供用户操作界面。

l 应用程序服务器:存在于所有客户端都可访问网络的中心用于提供数据服务。

l 远程数据服务器:提供关系数据库管理系统。

图4-4 三层应用程序结构图 三层应用程序开发人员主要使用Delphi开发客户端应用程序和应用程序服务器。对于最终用户来说,三层应用程序的客户端应用程序的外观和操作与传统的两层结构的使用缓存更新(cached update)的应用程序没有什么区别。在结构上,客户端应用程序更象单层结构应用程序,均使用data-aware控件显示数据集的数据。但是三层应用程序客户端的数据集使用应用服务器上的IAppServer界面获取和保存数据。客户端通过连接组件获得IAppServer界面,这些连接组件管理与应用服务器的连接,对于不同的通讯协议使用不同的连接组件。这些组件包括:TDCOMConnection,TSocketConnection,TWebConnection,TOLEnterpriseConnection,TCorbaConnection。三层应用程序客户端的数据集使用ClientDataSet,利用ClientDataSet的RemoteServer属性指定连接到应用服务器的连接组件名称,利用ProviderName指定向数据集提供数据的应用服务器DatasetProvider对象的名称。

应用程序服务器包括一个提供让客户端应用程序访问的IAppServer界面的远程数据模块,这些远程数据模块有三种类型:
TRemoteDataModule:这是一个双重接口自动操作服务器(dual-interface Automation server),如果客户端应用程序使用DCOM,HTTP,Sockets,或者OLEnterprise则可以使用这种类型。

TMTSDataModule:这是一个双重接口自动操作服务器(dual-interface Automation server),使用这种远程数据模块时应用程序服务器以.DLL动态连接库的形式与MTS一起安装。客户端应用程序使用DCOM,HTTP,Sockets,或者OLEnterprise。

TCorbaDataModule:是一个CORBA服务器,为CORBA客户端提供数据。

和任何数据模块一样,远程数据模块可以放置任何非可视化控件,另外还需要为每个应用程序服务器中可让客户端访问的数据集设置一个dataset provider组件。

接收客户端的数据请求,从数据库服务器取得请求的数据,把数据打包然后传送到客户端数据集,这个操作叫做“Providing(提供)”。

从客户端应用程序接收更新的数据,向数据库或源数据集提交数据,标记未能提交的数据,把未能更新的数据返回给客户端应用程序作处理的操作叫“Resolving”。

dataset provider通常象单层或两层应用程序那样使用BDE或ADO数据集,也可以根据需要使用数据库或会话组件。

4.4.2.2 MIDAS技术简介 Delphi的三层应用程序开发技术基于Multi-tier Distributed Application Services Suite(MIDAS)。客户端应用程序和应用程序服务器之间通过MIDAS.DLL通讯,MIDAS.DLL必须存在于windows\System或WINNT\System32目录下。

在MIDAS多层应用系统中,应用服务器会输出一个Provider接口到客户端应用程序,在这个接口中提供了许多方法可以让客户端应用程序调用,以便和远程应用程序服务器通讯,并且处理数据。

在多层应用系统中,客户端应用程序和应用程序服务器之间传递的数据都是通过一种由Inprise定义的,数据类型为OleVariant的数据封包形式传递。客户端应用程序和应用程序服务器之间传递的数据包括应用程序服务器传递给客户端的数据,客户端更新的数据,以及更新数据发生错误和造成错误的数据。MIDAS传递这些数据时会先压缩,然后再一次传送,可以大大地节省网络资源。

在客户端一开始连接了应用程序服务器之后,应用程序服务器就会从数据库中取出客户端需要的数据,建立新的数据封包,然后通过IAppServer接口以OleVariant的形式传递给客户端应用程序。当客户端收到数据封包后,就会通过客户端的MIDASServer整理,再加入到ClientDataSet的数据快储内存中。

当数据封包到达客户端并被解析成ClientDataSet的数据后,用户就可以对这些数据进行任何修改和更新工作,客户端的数据与数据库服务器的数据也就没有任何联系了,客户端和应用程序服务器之间的网络连接也会断开,不再使用任何网络资源。由于客户端中客户使用的数据都是存贮在客户端的内存或硬盘空间内,所以客户端处理数据的速度会非常迅速。

在客户端完成数据更新操作后,客户端应用程序可以调用TClientDataSet的ApplyUpdate方法把更新的数据提交到应用程序服务器请求数据更新。客户端只向应用程序服务器传递更新过的数据,对于没有更新过的数据不会被提交,这样也可以节省网络资源并且加快执行速度。回传的更新数据是封装在名字为Delta的数据封包中,应用程序服务器的Resolver负责解析Delta数据封包中的数据并且更新回数据库。

图4-5 三层读取数据流程图 图4-6 三层更新数据流程图 如果在更新的过程中发生错误,先调用应用服务器TdataSetProvider组件的OnUpdateError事件处理函数,再调用客户端TclientDataSet组件的OnReconcileError事件处理函数。

4.4.2.3 MIDAS 3.0 的新功能 Delphi5 使用3.0 版本的MIDAS。MIDAS 3.0 比MIDAS 2.0 有了重大的改善。MIDAS 3.0 实现了三个重要的目标,那就是执行效率,兼有状态对象和无状态对象的属性,以及给予程序有更大的弹性和控制权。

在MIDAS 3.0 中远程数据模块实现了IAppServer接口,他代替了Delphi 3/4 中的IDaraBroker接口同时也取消了用TProvider组件实现的IProvider接口。因此客户端的TClientDataSet要取得数据或更新数据时只要直接使用IAppServer接口之中的方法。取得IAppServer接口也只需要通过存取TClientDataSet的AppServer来实现。因此MIDAS 3.0可以大大减少客户端和应用程序服务器通讯时访问网络和接口的次数。

在状态对象和无状态对象上,MIDAS 3.0 的远程数据模块在默认上是一个无状态对象,当TclientDataSet从TdataSetProvider取得数据后TclientDataSet与TdataSetProvider的联系会断开,TdataSetProvider不用再维护TclientDataSet的任何信息,TdataSetProvider可以为其他TclientDataSet提供服务。所以Delphi5 的远程数据模块当使用MTS时可以加入对象pooling的机制让多个客户端应用程序重复使用。

第五章 总体设计 按照系统架构设计方案,医院住院信息管理系统分成出入院收费系统、住院病区管理系统和中心药房发药系统。各子系统由后台数据库系统,应用程序服务器和客户端程序组成,应用程序服务器负责为客户端程序提供企业对象的访问服务,客户端程序负责数据的输入和显示操作。

5.1 系统模块设计 5.1.1 出入院收费应用程序服务器 出入院收费应用程序服务器由主运行窗体,FinServer远程数据模块,DM本地数据模块,RmeciveRec线程类组成。功能结构如图5-1所示:
图5-1 出入院收费应用程序服务器功能结构图 5.1.1.1 主运行窗体 主要作用是启动应用程序服务器,包含一个定时器(TTimer)对象,用于定时启动ReciveRec线程从中心药房发药系统的数据接口接收中心药房系统的发药信息。

5.1.1.2 DM本地数据模块 主要作用是为ReciveRec线程类提供数据访问对象。包括一个TSession数据会话对象ses1;
两个TDatabase数据库连接对象medical和fin,分别用于连接中心药房数据库和出入院收费数据库;
四个TwwQuery对象分别用于被接收发药信息模块使用;
Tdm类有一个ReceiveRec公共方法用于被ReciveRec线程调用接收发药信息;
DM还有一个DoRecieve公共模块用于创建一个ReciveRec线程。

5.1.1.3 ReciveRec线程类 主要作用是从中心药房数据库接收发药信息。成员方法包括:Create用于线程初始化;
Execute用于执行线程;
oncomplete用于线程结束后释放临界区。

5.1.1.4 FinServer远程数据模块 主要作用是为出入院收费客户端提供数据访问服务。TFinServer类包括数据访问接口,服务调用接口和供本类方法调用的私有成员函数。下面是TFinServer类的声明:
TFinServer = class(TRemoteDataModule, IFinServer) Fin: TDatabase;//出入院数据库连接对象 NewReqRec: TwwQuery;//插入新的发药请求 NewReqRecMX: TwwQuery;//插入新的发药记录 qryPLorder: TwwQuery;//病人需要发药的长嘱 qryPSorder: TwwQuery;//病人需要发药的临嘱 bm1: TBatchMove;//数据传输对象 qryPReqRec: TwwQuery;//病人本次发药请求 qryPReqMX: TwwQuery;//病人本次发药非药品发药记录 NeedAddCost: TwwQuery;//本次发药中需要产生附加治疗的记录 upLPerformtime: TwwQuery;//更新长嘱最后执行时间 upSPerformtime: TwwQuery;//更新临嘱最后执行时间 qryPatInf: TwwQuery;//病人当前住院属性 qryGen: TwwQuery;//动态SQL查询对象 dspGen: TDataSetProvider;//动态SQL查询接口 upReqRec: TwwQuery;//传输发药请求后更新状态 upReqMX: TwwQuery;//传输发药记录后更新状态 medical: TDatabase;//中心药房数据库连接对象 tabMReqMX: TwwTable;//中心药房发药记录接口 tabReqRec: TwwTable;//中心药房发药请求接口 qryPMedReqMX: TwwQuery;//病人本次发药药品发药记录 qryPatient: TwwQuery;//病人资料对象 upPatient: TUpdateSQL;//病人资料更新对象 dspPatient: TDataSetProvider;//病人资料接口 qryCostArea: TwwQuery;//病人未结费用起止时间 qryPayInf: TwwQuery;//病人交费信息 dspPayInf: TDataSetProvider;//病人交费信息接口 qryPay: TwwQuery;//病人结算记录 dspPay: TDataSetProvider;//病人结算记录接口 qryCostList1: TwwQuery;//病人费用清单类型1 qryCostList2: TwwQuery;//病人费用清单类型2 dspCostList1: TDataSetProvider;//病人费用清单类型1接口 dspCostList2: TDataSetProvider;//病人费用清单类型2接口 qrySumCount: TwwQuery;//病人费用分类汇总 qrySumPrepay: TwwQuery;//病人住院押金合计 qryUnPay: TwwQuery;//病人未结费用汇总 dspUnPay: TDataSetProvider;//病人未结费用汇总接口 dspPrepay: TDataSetProvider;//病人住院押金明细接口 qryPrepay: TwwQuery;//病人住院押金明细 SetPatientIO: TwwQuery;//更新病人出院信息 SetPatientdata: TwwQuery;//更新病人资料 qrySorder: TwwQuery;//病人所有临嘱 dspSOrder: TDataSetProvider;//病人所有临嘱接口 tabOrdertimes: TwwTable;//医嘱的执行次数表 dspOrdertimes: TDataSetProvider;//医嘱的执行次数表接口 tabInsurance: TwwTable;//报销类型表 tabInsuKind: TwwTable;//社保类型表 tabInsuArea: TwwTable;//社保区域表 dspInsurance: TDataSetProvider;//报销类型表接口 dspInsuKind: TDataSetProvider;//社保类型表接口 dspInsuArea: TDataSetProvider;//社保区域表接口 tabSex: TwwTable;//性别表 dspSex: TDataSetProvider;//性别表接口 upPrepay: TUpdateSQL;//住院押金更新对象 PatientIn: TQuery;//生成病人住院记录 upPatientInf: TQuery;//更新病人资料 upPatientIO: TQuery;//更新病人住院记录 qryPALOrder: TwwQuery;//病人所有长嘱 dspPALOrder: TDataSetProvider;//病人所有长嘱接口 dspPASOrder: TDataSetProvider;//病人所有临嘱接口 qryPASOrder: TwwQuery;//病人所有临嘱 qryCZD: TwwQuery;//冲正记录明细 qryCZM: TwwQuery;//冲正记录汇总 dspCZD: TDataSetProvider;//冲正记录明细接口 dspCZM: TDataSetProvider;//冲正记录汇总接口 qryACost: TwwQuery;//查询冲正附加费用 dspACost: TDataSetProvider;//查询冲正附加费用接口 dspCZCost: TDataSetProvider;//查询费用冲正数量接口 sumCZCost: TwwQuery;//查询费用冲正数量 sumCZACost: TwwQuery;//查询附加费用冲正数量 dspCZACost: TDataSetProvider;//查询附加费用冲正数量接口 qryPCZ: TwwQuery;//查询某医嘱的冲正记录 dspPCZ: TDataSetProvider;//查询某医嘱的冲正记录接口 qryPCZA: TwwQuery;//查询某医嘱的附加治疗的冲正记录 dspPCZA: TDataSetProvider;//查询某医嘱的附加治疗的冲正记录接口 upPCZ: TUpdateSQL;//费用冲正记录更新对象 upPCZA: TUpdateSQL;//附加费用冲正记录更新对象 qryPCZCost: TQuery;//病人本次冲正记录 upCZPerform: TwwQuery;//更新冲正记录的执行状态 qryIncomeInf: TwwQuery;//统计收入分类汇总 qryOtherFee: TwwQuery;//查询病区伙食、生活品收入情况 qryCashIn: TwwQuery;//统计现金收入 qryTotDayprepay: TwwQuery;//统计住院押金收入 qryDayPrepay: TwwQuery;//查询收费员当天住院押金明细 qryFaP: TwwQuery;//收费员当天开出发票明细 dspDayPrepay: TDataSetProvider;//查询收费员当天住院押金明细接口 dspFaP: TDataSetProvider;//收费员当天开出发票明细接口 upDayPrepay: TUpdateSQL;//收费员住院押金更新对象 upSOrder: TUpdateSQL;//更新病人临嘱对象 InsCost: TwwQuery;//保存费用记录 dspInsCost: TDataSetProvider;//保存费用记录接口 InsCZ: TwwQuery;//保存费用冲正记录 dspInsCZ: TDataSetProvider;//保存费用冲正记录接口 deleCost: TwwQuery;//删除临时费用记录 dspdeleCost: TDataSetProvider;//删除临时费用记录接口 deleCZ: TwwQuery;////删除临时费用冲正记录 dspDeleCZ: TDataSetProvider;//删除临时费用冲正记录接口 dspInsFP: TDataSetProvider;//保存发票接口 InsFP: TwwQuery;//保存发票 InsPay: TwwQuery;//保存结算信息 InsCash: TwwQuery;//保存现金信息 dspInsPay: TDataSetProvider//保存结算信息接口; dspInsCash: TDataSetProvider;//保存现金信息接口 InsICCard: TwwQuery;//保存ICCARD信息 dspInsICCard: TDataSetProvider;//保存ICCARD信息接口 upFPNo: TwwQuery;//更新发票号码 dspupFPNo: TDataSetProvider;//更新发票号码接口 updatePrepay: TwwQuery;//更新住院押金记录状态 dspupPrepay: TDataSetProvider;//更新住院押金记录状态接口 qryPay2: TwwQuery;//结算信息 dspPay2: TDataSetProvider;//结算信息接口 dspFP: TDataSetProvider;//发票信息接口 qryFP: TwwQuery;//发票信息 qryIC: TwwQuery;//结算中ICCard收款 qryCash: TwwQuery;//结算中现金收款 dspIC: TDataSetProvider;//结算中ICCard收款接口 dspCash: TDataSetProvider;//结算中现金收款接口 upPaydata: TQuery;//更新结算记录中交款金额字段 dspUpPaydata: TDataSetProvider;//更新结算记录中交款金额字段接口 LoadOC: TwwQuery;//向临时费用表装入费用记录 delOrdercost: TwwQuery;//删除费用记录表中的费用记录 delePay: TwwQuery;//作废结算记录 delePrepay: TwwQuery;//作废结算记录接口 SaveLOrder: TwwQuery;//保存长嘱 SaveSOrder: TwwQuery;//保存临嘱 SaveAOrder: TwwQuery;//保存附加治疗医嘱 SaveCZ: TwwQuery;//保存冲正记录 DeleteLOrder: TwwQuery;//删除长嘱 DeleteSOrder: TwwQuery;//删除临嘱 DeleteAOrder: TwwQuery;//删除附加治疗医嘱 DeleteCZ: TwwQuery;//删除冲正记录 qryUnperfrom: TwwQuery;//查询未确认的费用记录 dspUnPerform: TDataSetProvider;//查询未确认的费用记录接口 qryBank: TwwQuery;//银行表 dspBank: TDataSetProvider;//银行表接口 qryIntimes: TwwQuery;//病人历次住院明细 dspIntimes: TDataSetProvider;//病人历次住院明细接口 dspTimesFee: TDataSetProvider;//汇总住院费用接口 qryTimesFee: TwwQuery;//汇总住院费用 qryCode: TwwQuery;//代码查询 dspCode: TDataSetProvider; //代码查询接口 procedure dspPatientBeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean); procedure dspPrepayBeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean); procedure dspPCZBeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean); procedure dspPCZABeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean); procedure dspSOrderBeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean); private { Private declarations } //判定医嘱是否需要执行 function NeedCreatRec(DDay:TDatetime;Source:TDataset):integer; //产生发药记录 function CreatReqRecMX(DDay:TDatetime;Source:TDataset;lors:integer):integer; //产生发药请求 function CreatReqRec(DDay:TDatetime;inid:integer;lors:integer):integer; //产生附加治疗费用 Procedure CreatAddCost(DDay:TDatetime;inid:integer;intimes:integer); //设定更新字段值 procedure SetParams(FUpdateSQL:TUpdateSQL;DeltaDS:TClientDataSet;UpdateKind:TUpdateKind); //保存医嘱 Procedure SaveOrder(inid,intimes:integer); protected class procedure UpdateRegistry(Register: Boolean; const ClassID, ProgID: string); override; //对病人的医嘱产生发药记录 procedure PerformOrder(inid, intimes: Integer; wardid: OleVariant; dday: TDateTime); safecall; //病人发药 procedure PPerformOrder(inid, intimes: Integer; wardid: OleVariant); safecall; //统计病人费用 procedure CountPatientFee (inid, intimes: Integer; var totfee: OleVariant; day1, day2: TDateTime); safecall; //办理病人出院 procedure SetPatientOut(inid, intimes: Integer; OutDoc, OutWard: OleVariant; var ReValue: OleVariant); safecall; //办理病人入院 procedure PatientCheckIn(inid, intimes, payid, state: Integer; inward, indoc: OleVariant; indate: TDateTime); safecall; //病人执行冲正 procedure PerformCZ(inid, intimes: Integer; wardid: OleVariant); safecall; //查询收费员业务资料 procedure GetDayInfo(var Dec: OleVariant; op: Integer; day, day1: TDateTime); safecall; //作废结算 procedure SetPayDelete(Inid, intimes, op: Integer; pay: Double); safecall; public { Public declarations } end; 5.1.2 出入院收费系统客户端 出入院收费系统客户端的主要功能是为办理病人的出入院手续,收费等操作提供操作界面。其模块结构如图5-2所示:
图5-2 出入院收费系统客户端模块结构图 5.1.2.1 全局数据模块dm:Tdm 主要作用是提供与出入院收费应用服务器的连接finance: TDCOMConnection和供其他模块调用的通用过程。他们包括:
procedure CountQianKuan(inid:integer;intimes:integer;var data:QianFeeDan) 作用是计算病人欠费单的参数;

function SmallToBig(small:double):string; 作用是把小写金额转变成大写;

procedure StoreFPNo(Sour:TDataset; Dec:Tstrings; column:integer; n:integer; spac:string); 作用是把发票或单据号码按连续的号码分组,然后写到目的TStrings对象中;

function Uplimit(x:double):integer; 作用是求浮点数的最大整数;

qryGen: TwwClientDataSet,作用是向出入院收费应用服务器传送动态SQL语句并接收返回结果。

5.1.2.2 收费员操作模块 fShouFee: TfShouFee 为客户端程序的主控模块,主要作用是显示当前收费员当天业务发生情况和调用其他功能模块 5.1.2.3 病人资料管理模块 frmPatient: TfrmPatient 主要作用是查询、增加病人,修改病人资料,调用病人交费查询模块,病人住院押金管理模块、病人住院费用汇总模块,病人费用结算模块,办理病人入院或转科模块,社保病人社保属性设定模块。

模块中利用对象qryPatient: TwwClientDataSet与应用服务器的dspPatient: TDataSetProvider接口取得病人的基本资料。模块内部调用的成员方法有:
procedure EnableEdit(); 作用是激活对病人资料属性的修改;

procedure DisableEdit(); 作用是关闭对病人资料属性的修改;

procedure EnableButton(); 作用是激活功能模块调用按钮;

procedure DisableButton(); 作用是关闭功能模块调用按钮;

5.1.2.4 病人交费查询模块frmPay: TfrmPay 作用是显示病人历次结算信息,打印欠费单和住院费用清单。

5.1.2.5病人住院押金管理模块 frmPrepay: TfrmPrepay 作用是管理病人本次住院的住院押金,可以增加和作废。

5.1.2.6办理病人入院或转科模块 frmCheckIn: TfrmCheckIn 作用是设定办理病人入院或转科的几个参数:入院时间、入院科室和办理入院的医师,然后调用应用服务器的PatientCheckIn过程办理病人入院。

5.1.2.7病人住院费用汇总模块 frmPIntimes: TfrmPIntimes 作用是显示病人历次住院的费用汇总,并可以打印。

5.1.2.8社保病人社保属性设定模块 frmSetInsu: TfrmSetInsu 作用是设定参加社保的病人的本次住院的社保类型,工作序号和住院次数。

5.1.2.9病人费用结算模块 fPatientFee: TfPatientFee 作用是为病人办理结算,设定病人结算费用的时间阶段,结算的住院押金单据,计算病人应补交金额和输入病人实际补交数。在此模块中可以调用补充病人费用模块,冲正费用模块,查阅发票模块,打印发票模块,病人住院费用汇总模块。

模块的主要成员方法有:
procedure GetUnpay(inid:integer);//计算未结算费用阶段 procedure ShowData();//显示费用信息 procedure ComputFee();//计算费用,包括住院费用和社保费用 function GetPrepay():double;//计算要结算的按金金额 procedure ShowPatInf (inid:integer;intimes:integer); procedure ShowCost (inid:integer;intimes:integer);//显示病人费用信息 procedure SetFP ();//设定发票数据 procedure SetPatientOut ();//设定为出院结算 5.1.2.10 补充病人费用模块 fAddition: TfAddition 主要作用是把需要补充录入的医嘱追加到临时医嘱中,然后再作补充发药。

5.1.2.11 病人住院费用冲正模块 主要作用是显示病人本次住院的所有长期医嘱和临时医嘱供操作员在执行具体冲正操作时选择,并且显示所有医嘱的费用冲正情况。在执行具体医嘱冲正操作时调用执行冲正模块。

5.1.2.12 医嘱冲正模块 frmOPCZ: TfrmOPCZ 作用是对选定的医嘱做费用冲正操作,模块中显示当前医嘱的费用情况和附加治疗的费用情况,操作员可以冲正当前医嘱和所属附加治疗的执行次数。冲正确认后要调用应用服务器退药的过程PerformCZ,待中心药房系统确认退药后才能冲减费用。

5.1.2. 13打印发票模块 FP: TFP 作用是做结算的确认操作,记录结算信息、发票信息、现金收款和ICCard收款信息,把参加结算 的费用记录保存到历史表中,然后从临时表中删除原费用记录。

5.1.2.14 查阅发票模块 fFPInf: TfFPInf 作用是显示某次结算的资料,包括发票信息,收款信息,重新打印发票。若本次结算病人为立欠(交款不足),可以补交款,还可以调用服务器SetPayDelete方法作废发票。

5.1.3 病区管理应用服务器 病区管理应用程序服务器结构与出入院收费应用程序服务器相似由主运行窗体,WardServer远程数据模块,DM本地数据模块,MakeDailyList线程类组成。

图5-3病区管理应用服务器功能结构图 5.1.3.1 WardServer远程数据模块 主要作用是为住院病区客户端提供数据访问服务。TWardServer类包括数据访问接口,方法调用接口和供本类方法调用的私有成员函数。下面是TWardServer类的声明:
TWardServer = class(TRemoteDataModule, IWardServer) WardDB: TDatabase;//与病区数据库的连接 qryPLorder: TwwQuery;//病人要发药的长期医嘱 NewReqRecMX: TwwQuery;//新增一条发药记录 NewReqRec: TwwQuery;//新增一条发药请求 qryPatInf: TwwQuery;//病人资料 finance: TDatabase;//与出入院数据库的连接 medical: TDatabase;//与中心药房数据库的连接 NeedAddCost: TwwQuery;//需要执行的附加治疗 upLPerformtime: TwwQuery;//更新长嘱最后执行时间 upSPerformtime: TwwQuery;//更新临嘱最后执行时间 qryPSorder: TwwQuery;//病人要发药的临时医嘱 qryLorder: TwwQuery;//病人当前长嘱 UpdateSQLlorder: TUpdateSQL;//病人当前长嘱更新对象 dspLorder: TDataSetProvider;//病人当前长嘱接口 qrySorder: TwwQuery;//病人当前临嘱 UpdateSQLSorder: TUpdateSQL;//病人当前长嘱更新对象 dspSorder: TDataSetProvider;//病人当前长嘱接口 qryAddorder : TwwQuery;//病人当前附加医嘱 qryCostInfo : TwwQuery ;//病人费用资料 qryWardPatient: TwwQuery;//病区病床 dspWardPatient: TDataSetProvider;//病区病床接口 tabOTimes: TwwTable;//医嘱执行次数表 tabPerform: TwwTable;//医嘱用法表 dspOTimes: TDataSetProvider;//医嘱执行次数接口 dspPerform: TDataSetProvider;//医嘱用法表接口 tabOperator: TwwTable;//操作员表 dspOperator: TDataSetProvider;//操作员表接口 tabDoctor: TwwTable;//医生表 dspDoctor: TDataSetProvider;//医生表接口 qryGen: TwwQuery;//动态SQL语句查询 dspGen: TDataSetProvider; //动态SQL语句查询接口 dspAddorder: TDataSetProvider;//病人当前附加医嘱接口 qryCode: TwwQuery;//代码查询 dspCode: TDataSetProvider;//代码查询接口 upPatio: TwwQuery;//更新病人入院记录 upPatin: TwwQuery;//更新病人资料 qryPatientIn: TwwQuery;//病人住院信息 bm1: TBatchMove;//数据传送对象 tabPatient: TTable;//病人资料表 upBed: TQuery;//病人转入病床 qryPReqMX: TwwQuery;//病人非药物治疗记录 qryPMedReqMX: TwwQuery;//病人药物发药记录 qryPReqRec: TwwQuery;//病人发药请求 tabMReqMX: TwwTable;//中心药房数据库接口 tabFReqMX: TwwTable;//出入院数据库接口 tabReqRec: TwwTable;//中心药房发药请求接口 upReqMX: TwwQuery;//更新发药记录状态 upReqRec: TwwQuery;//更新发药请求状态 qryPPatient: TwwQuery;//查询病人资料 qryWReqMX: TwwQuery;//病区发药非药物发药记录 qryWMedReqMX: TwwQuery;//病区发药药物发药记录 qryWReqRec: TwwQuery;//病区发药请求 upWReqMX: TwwQuery;//更新病区发药记录状态 upWReqRec: TwwQuery;//更新病区发药请求状态 qryPALorder: TwwQuery;//病人所有长嘱 qryPASorder: TwwQuery;//病人所有临嘱 dspPALorder: TDataSetProvider;//病人所有长嘱接口 dspPASorder: TDataSetProvider;//病人所有临嘱接口 qryCZM: TwwQuery;//冲正记录汇总 qryCZD: TwwQuery;//冲正记录明细 dspCZD: TDataSetProvider;//冲正记录明细接口 dspCZM: TDataSetProvider;//冲正记录汇总接口 sumCZCost: TwwQuery;//查询费用冲正数量 dspCZCost: TDataSetProvider;//查询费用冲正数量接口 dspCZACost: TDataSetProvider;//查询附加费用冲正数量 sumCZACost: TwwQuery;//查询附加费用冲正数量接口 qryACost: TwwQuery;//查询冲正附加费用 dspACost: TDataSetProvider;//查询冲正附加费用接口 dspPCZ: TDataSetProvider;//查询某医嘱的冲正记录 qryPCZ: TwwQuery;//查询某医嘱的冲正记录接口 qryPCZA: TwwQuery;//查询某医嘱的附加治疗的冲正记录 dspPCZA: TDataSetProvider;//查询某医嘱的附加治疗的冲正记录接口 upAddOrder: TUpdateSQL;//附加治疗项目更新对象 qryGen2: TwwQuery;//出入院数据库动态SQL语句查询 dspGen2: TDataSetProvider;//出入院数据库动态SQL语句查询接口 cleanPatient: TwwQuery;//病床删除病人 qryBed: TwwQuery;//科室病床 dspBed: TDataSetProvider;//科室病床接口 UpdateBed: TUpdateSQL;//科室病床更新对象 qryNurseClass: TwwQuery;//病人护理级别 updateNurse: TwwQuery;//更新病人护理级别 qryPReqMX2: TwwQuery;//病人发药药物发药记录 upPCZ: TUpdateSQL;//费用冲正记录更新对象 upPCZA: TUpdateSQL;//附加费用冲正记录更新对象 qryPCZCost: TQuery;//病人本次冲正记录 upCZPerform: TwwQuery;//更新冲正记录的执行状态 qryWReqMX2: TQuery;//病区发药药物发药记录 StopOrder: TwwQuery;//停止所有长期医嘱 qryAllLorder: TwwQuery;//病人所有长嘱 qryAllSorder: TwwQuery;//病人所有临嘱 qryAllCZ: TwwQuery;//病人所有冲正记录 qryAllADD: TwwQuery;//病人所有附加治疗项目 tabFLOrder: TwwTable;//出入院接收长嘱接口 tabFSOrder: TwwTable;//出入院接收临嘱接口 tabFAOrder: TwwTable;//出入院接收附加治疗项目接口 tabFCZ: TwwTable;//出入院接收冲正记录接口 upStat1: TwwQuery;//更新病区数据库病人状态 upStat2: TwwQuery;//更新出入院数据库病人状态 qryDailyList: TwwQuery;//病人费用每日清单 dspDailyList: TDataSetProvider;//病人费用每日清单接口 procedure dspSorderBeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean); procedure dspLorderBeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean); procedure dspAddorderBeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean); procedure dspBedBeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean); procedure dspPCZBeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean); procedure dspPCZABeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean); private { Private declarations } //判定医嘱是否需要执行 function NeedCreatRec(DDay:TDatetime;Source:TDataset):integer; //产生发药记录 function CreatReqRecMX(DDay:TDatetime;Source:TDataset;lors:integer):integer; //产生发药请求 function CreatReqRec(DDay:TDatetime;inid:integer;lors:integer):integer; //产生附加治疗费用 Procedure CreatAddCost(DDay:TDatetime;inid:integer;intimes:integer); //设定更新字段值 procedure SetParams(FUpdateSQL:TUpdateSQL;DeltaDS:TClientDataSet;UpdateKind:TUpdateKind); protected class procedure UpdateRegistry(Register: Boolean; const ClassID, ProgID: string); override; //对病人的医嘱产生发药记录 procedure PerformOrder(inid, intimes: Integer; Wardid: OleVariant; DDay: TDateTime); safecall; //查询病人住院费用 procedure PatientCostInf(inid, intimes: Integer; var info: OleVariant); safecall; //接收入院病人 procedure PatientCheckIn(inid, intimes: Integer; wardid, docnum, bed: OleVariant); safecall; //病人发药 procedure PPerformOrder(inid, intimes: Integer; wardid: OleVariant); safecall; //病区发药 procedure WPerformOrder(wardid: OleVariant); safecall; //更新护理级别 procedure UpdateNurseClass(inid, intimes, payid: Integer); safecall; //病人执行冲正 procedure PerfromCZ(inid, intimes: Integer; wardid: OleVariant); safecall; //病人办理出院、转科或阶段结帐 procedure PatientOut(inid, intimes, payid: Integer; wardid: OleVariant; Mode: Integer); safecall; //病区生成每日费用清单 procedure WardMakeDailyList(wardid: OleVariant; listdate: TDateTime); safecall; public { Public declarations } end; 5.1.3.2 DM本地数据模块 主要作用是为MakeDailyList线程类提供数据访问对象。包括一个TSession数据会话对象ses2;
两个TDatabase数据库连接对象db1和db2,分别用于连接中心药房数据库和出入院收费数据库;
三个TwwQuery对象分别用于产生每日费用清单模块使用;
Tdm类有一个MakeDaily公共方法用于被MakeDailyList线程调用接收发药信息;
DM还有一个WMakeDailyList公共模块用于创建一个MakeDailyList线程。

5.1.3.3 MakeDailyList线程类 主要作用是从出入院收费数据库接收费用信息,然后产生每日费用清单。成员方法包括:Create用于线程初始化;
Execute用于执行线程;
oncomplete用于线程结束后释放临界区。

5.1.3.4 主运行窗体 主要作用是启动应用程序服务器,包含一个定时器(TTimer)对象,用于定时启动MakeDailyList线程产生每日费用清单。

5.1.4 住院病区管理客户端 住院病区管理客户端的作用是为住院病区接收病人入院、录入医嘱、发药、办理出院等操作提供操作界面。

图5-4住院病区管理客户端模块结构图 5.1.4.1 全局数据模块dm:Tdm 主要作用是提供与出入院收费应用服务器的连接ward: TDCOMConnection和供其他模块使用的数据访问对象。

5.1.4.2 主运行窗体 frmMain: TfrmMain 为客户端程序的主控模块,负责显示本病区现有病床的使用情况和在院病人的状态和护理级别,调用其他的功能模块。模块内主要成员方法包括:
//打开当前病人的医嘱 procedure openorder; //刷新床位使用情况和病人状态和护理级别 procedure BedListRefesh(wardid:string); //清空当前床位 procedure ClearBed(); //病人转床 ChangeBed(source:Tlistitem;dec:Tlistitem) 5.1.4.3 医嘱录入模块 frmOrderIn: TfrmOrderIn 主要作用是录入病人医嘱和为单个病人发药。病人的长期医嘱和临时医嘱以网格控件显示,窗体左下方还有一个网格控件显示当前医嘱所对应的附加治疗项目。通过对网格控件的控制可以对医嘱的录入实现输入、修改、删除控制,自动输入等功能。

5.1.4.4 病人住院费用冲正模块 主要作用是显示病人本次住院的所有长期医嘱和临时医嘱供操作员在执行具体冲正操作时选择,并且显示所有医嘱的费用冲正情况。在执行具体医嘱冲正操作时调用执行冲正模块。

5.1.4.5 医嘱冲正模块 frmOPCZ: TfrmOPCZ 作用是对选定的医嘱做费用冲正操作,模块中显示当前医嘱的费用情况和附加治疗的费用情况,操作员可以冲正当前医嘱和所属附加治疗的执行次数。冲正确认后要调用应用服务器退药的过程PerformCZ,待中心药房系统确认退药后才能冲减费用。

5.1.4.6 每日费用清单模块 frmMDL: TfrmMDL 可以选择产生或打印某天的每日费用清单。

5.1.4.7 办理出院模块 frmPatientOut: TfrmPatientOut 作用是设定应用服务器方法PatientOut的参数,办理病人出院、转科或阶段结帐。

5.1.4.8 接收入院病人模块 frmPatientIn: TfrmPatientIn 作用是设定入院病人的床位、住院医生然后调用服务器方法PatientCheckIn接收入院病人。

5.1.5 中心药房应用服务器 中心药房应用程序服务器结构与出入院收费应用程序服务器相似由主运行窗体,MeddServer远程数据模块,DM本地数据模块,PerformMedReq线程类组成。

图5-5 中心药房应用服务器功能结构图 5.1.5.1 主窗体 启动应用服务器。

5.1.5.2 远程数据模块 TMedServer 主要作用是为中心药房客户端提供数据访问服务。TMedServer类包括数据访问接口,方法调用接口和供本类方法调用的私有成员函数。下面是TMedServer类的声明:
TMedServer = class(TRemoteDataModule, IMedServer) db1: TDatabase;//中心药房数据库连接 qryReqRecGroup: TwwQuery;//发药请求分类 qryReqRec: TwwQuery;//发药请求 qryReqRecMX: TwwQuery;//当前发药请求的发药记录集 dspReqRecGroup: TDataSetProvider;//发药请求分类接口 dspReqRec: TDataSetProvider;//发药请求接口 dspReqRecMX: TDataSetProvider;//当前发药请求的发药记录集接口 qryGen: TwwQuery;//动态SQL查询 dspGen: TDataSetProvider;//动态SQL查询接口 ses3: TSession;//会话对象 procedure RemoteDataModuleCreate(Sender: TObject); procedure RemoteDataModuleDestroy(Sender: TObject); private { Private declarations } performThread:PerformMedReq;//发药线程 procedure CompletePerform(Sender:TObject);//发药后处理过程 protected class procedure UpdateRegistry(Register: Boolean; const ClassID, ProgID: string); override; //执行发药方法 procedure PerformReq(inid: Integer; Reqid: TDateTime; data: OleVariant; op: Integer); safecall; public { Public declarations } end; 5.1.5.3 全局数据模块 dm:Tdm 为发药线程PerformMedReq提供数据访问对象。

5.1.5.4 发药线程类 PerformMedReq 由客户端触发,根据客户端对发药记录的设定情况作确认和扣减药品库存量的操作,同一时间只有一条发药线程在运行。

5.1.6 中心药房客户端程序 中心药房客户端程序的主要功能是显示各病区传送过来的发药信息,向中心药房应用服务器指示发药操作。

图5-6 中心药房客户端程序模块结构图5-6 5.1.6.1 全局数据模块 dm:Tdm 提供主模块使用的数据访问对象。

5.1.6.2 发药操作模块 frmMain: TfrmMain 按发药科室和发药时间分类发药请求,对每位病人的发药请求按长期医嘱、临时医嘱、冲正药品分类显示。调用应用服务器方法PerformReq出发应用服务器发药操作。

5.2 数据结构设计 5.2.1 系统数据库ER图 5.2.2 系统数据表结构 (1)病人资料表Patientdata KEY:Inid 序号 字段名 字段含义 数据类型 是否为空 1 Inid 住院号 int 否 2 Name 姓名 Varchar(10) 是 3 IDcard 身份证号 Varchar(18) 是 4 Sex 性别 smallint 是 5 Brithday 生日 datetime 是 6 Hometown 籍贯 Varchar(10) 是 7 Address 地址 varchar(50) 是 8 Post 邮政编码 varchar(6) 是 9 Phone 电话 varchar(30) 是 10 Unit 单位 varchar(50) 是 11 dwaddr 单位地址 varchar(50) 是 12 dwtele 单位电话 varchar(13) 是 13 dwpost 单位邮编 varchar(6) 是 14 Country 国籍 varchar(10) 是 15 Insurance 医疗保险 smallint 是 16 Iccard 社保ICCard号 varchar(20) 是 17 Intimes 住院次数 int 是 18 Payid 结算次数 int 是 19 Preout 预出院 int 是 20 Inward 住院科室 varchar(4) 是 21 Stat 状态 int 是 22 Indate 入院时间 datetime 是 23 Outdate 出院时间 datetime 是 24 connect 联系人 varchar(10) 是 25 ConAddress 联系地址 varchar(50) 是 26 ConPhone 联系电话 varchar(30) 是 27 ConUnit 联系人单位 varchar(50) 是 28 Relationship 与病人关系 varchar(10) 是 29 Operator 操作员 int 是 30 Nurse 护理级别 int 是 31 InsuArea 社保区域 smallint 是 32 PatientKind 病人类型 smallint 是 33 Docnum 住院医生 varchar(10) 是 附:Stat:“0”-新病人;
“1”-等待入院;
“2”-住院;
“3”-阶段结算;
“4”-办理出院;
“5”-已出院;
“6”-转科。

Sex:“0”-女;
“1”-男。

Insurance:“0”-公费;
“1”-劳保;
“2”-医疗保险;
“3”-自费。

(2)病人住院记录表 PatientIO KEY:Inid+Intimes 序号 字段名 字段含义 数据类型 是否为空 1 Inid 住院号 int 否 2 Intimes 住院次数 int 否 3 InWard 入院科室 varchar(4) 是 4 OutWard 出院科室 varchar(4) 是 5 InDate 入院时间 datetime 是 6 OutDate 出院时间 datetime 是 7 InsuNo 社保工作序号 Varchar(10) 是 8 InsuKind 社保类型 smallint 是 9 InsuTimes 社保住院次数 smallint 是 10 InDoc 介绍入院医生 varchar(5) 是 11 WardDoc 住院主管医生 varchar(5) 是 12 OutDoc 出院医生 varchar(5) 是 (3)病人住院押金表 Prepay Key: Inid+timestemp 序号 字段名 字段含义 数据类型 是否为空 1 Inid 住院号 int 否 2 Intimes 住院次数 int 否 3 PayDate 交款日期 datetime 是 4 BillNo 收据号 varchar(20) 是 5 Prepay 押金金额 numeric(18, 2) 是 6 OperatorNo 操作员号 int 是 7 Delet 作废标志 smallint 是 8 DeleDate 作废日期 datetime 是 9 DeleOperator 作废操作员号 int 是 10 timestemp 录入时间 datetime 是 11 State 状态 smallint 是 12 Pay 结算标识 float 是 (4)病人结算表 Paydata Key:Pay 序号 字段名 字段含义 数据类型 是否为空 1 Inid 住院号 int 是 2 Wardid 病区号 Varchar(4) 是 3 Intimes 住院次数 int 是 4 Payid 结算次数 int 是 5 begindat 费用开始日期 datetime 是 6 Enddate 费用结束日期 datetime 是 7 Drugfe 药费 numeric(18, 2) 是 8 CDrugfee 中药费 numeric(18, 2) 是 9 Treatfee 治疗费 numeric(18, 2) 是 10 Examfee 化验费 numeric(18, 2) 是 11 Checkfee 检查费 numeric(18, 2) 是 12 CTfee CT费 numeric(18, 2) 是 13 Bedfee 床位费 numeric(18, 2) 是 14 Diagnosefee 诊金 numeric(18, 2) 是 15 Nursfee 护理费 numeric(18, 2) 是 16 Foodfee 膳食费 numeric(18, 2) 是 17 Lifefee 生活品费 numeric(18, 2) 是 18 Operatfee 手术费 numeric(18, 2) 是 19 Otherfee 其他费用 numeric(18, 2) 是 20 Prepay 住院押金 numeric(18, 2) 是 21 Paytype 结算方式 int 是 22 Paydate 计算时间 datetime 是 23 Billno 发票号码 varchar(20) 是 24 Operator 收费员号 int 是 25 Isdele 作废标志 int 是 26 Deledate 作废时间 datetime 是 27 Deleoperator 作废收费员号 int 是 28 timestemp 产生时间 datetime 是 29 Insurance 社保负担金额 numeric(18, 2) 是 30 Self 个人自负金额 numeric(18, 2) 是 31 Sumcost 住院费用总额 numeric(18, 2) 是 32 Sumpay 总支付额 numeric(18, 2) 是 33 Pay 结算标识 float 否 34 State 状态 smallint 是 35 InsuType 社保结算类型 smallint 是 36 Paied 个人已支付 numeric(18, 2) 是 附:State: “0”-正常;
“1”-欠款;
“2”-作废 (5)发票内容表 Paydata Key: Pay 序号 字段名 字段含义 数据类型 是否为空 1 Pay 结算标识 float 否 2 FpNo 发票号码 int 是 3 timestemp 产生时间 datetime 是 4 FPdat 发票日期 datetime 是 5 Drugfe 药费 numeric(18, 2) 是 6 CDrugfee 中药费 numeric(18, 2) 是 7 Treatfee 治疗费 numeric(18, 2) 是 8 Examfee 化验费 numeric(18, 2) 是 9 Checkfee 检查费 numeric(18, 2) 是 10 CTfee CT费 numeric(18, 2) 是 11 Bedfee 床位费 numeric(18, 2) 是 12 Diagnosefee 诊金 numeric(18, 2) 是 13 Nursfee 护理费 numeric(18, 2) 是 14 Foodfee 膳食费 numeric(18, 2) 是 15 Lifefee 生活品费 numeric(18, 2) 是 16 Operatfee 手术费 numeric(18, 2) 是 17 Otherfee 其他费用 numeric(18, 2) 是 18 Inid 住院号 int 是 19 Intimes 住院次数 int 是 (6)现金收款记录 Cashpay Key: Pay+timestemp 序号 字段名 字段含义 数据类型 是否为空 1 Pay 结算标识 float 否 2 timestemp 产生时间 datetime 否 3 Inid 住院号 int 是 4 Intimes 住院次数 int 是 5 Paydate 发票日期 datetime 是 6 Cash 收款金额 numeric(18, 2) 是 7 Operator 收费员号 int 是 8 Billno 发票号 int 是 (7)ICCard收款记录 ICCard Key: Pay+timestemp 序号 字段名 字段含义 数据类型 是否为空 1 Pay 结算标识 float 否 2 timestemp 产生时间 datetime 否 3 Inid 住院号 int 是 4 Intimes 住院次数 int 是 5 Bank 银行号 int 是 6 CardNo Card号码 varchar(20) 是 7 JE 收款金额 numeric(18, 2) 是 8 Operator 收费员号 int 是 9 Paydate 收款日期 datetime 是 (8)长期医嘱表 Lorderitem Key: Inid+timestemp 序号 字段名 字段含义 数据类型 是否为空 1 Inid 住院号 float 否 2 timestemp 产生时间 datetime 否 3 Intimes 住院次数 int 是 4 Wardid 住院病区 varchar(4) 是 5 StartTime 开始时间 datetime 是 6 StopTime 结束时间 datetime 是 7 Ordercode 项目代码 varchar(6) 是 8 Dose 剂量 numeric(18, 2) 是 9 Ordertimes 次数号 int 是 10 Performcode 用法号 int 是 11 Performid 执行序号 int 是 12 Payid 结算号 int 是 13 PerformPlace 执行地点 varchar(4) 是 14 isstop 停止标志 smallint 是 15 sure 确认标志 smallint 是 16 Operator 录入人 int 是 17 sureop 确认人 int 是 18 Docnum 住院医生号 varchar(5) 是 19 LastPerform 最后执行时间 datetime 是 (9)临时医嘱表 Sorderitem Key: Inid+timestemp 序号 字段名 字段含义 数据类型 是否为空 1 Inid 住院号 inid 否 2 Intimes 住院次数 int 否 3 timestemp 产生时间 datetime 是 4 Wardid 住院病区 varchar(4) 是 5 OrderTime 医嘱执行时间 datetime 是 6 Ordercode 项目代码 varchar(6) 是 7 Dose 剂量 numeric(18, 2) 是 8 Ordertimes 次数号 int 是 9 Performcode 用法号 int 是 10 Performid 执行序号 int 是 11 Payid 结算号 int 是 12 PerformPlace 执行地点 varchar(4) 是 13 sure 确认标志 smallint 是 14 Operator 录入人 int 是 15 sureop 确认人 int 是 16 Docnum 住院医生号 varchar(5) 是 17 LastPerform 最后执行时间 datetime 是 (10)附加治疗表 Addorderitem Key: Inid+timestemp 序号 字段名 字段含义 数据类型 是否为空 1 Inid 住院号 inid 否 2 Intimes 住院次数 int 是 3 Payid 结算号 int 是 4 Wardid 住院病区 varchar(4) 是 5 lors 医嘱执行时间 smallint 是 6 Performid 执行序号 int 是 7 Ordercode 项目代码 varchar(6) 是 8 Dose 剂量 numeric(18, 2) 是 9 timestemp 产生时间 datetime 否 10 Docnum 住院医生号 varchar(5) 是 (11)冲正记录表 CZCost Key: Inid+Itemid+timestemp 序号 字段名 字段含义 数据类型 是否为空 1 Inid 住院号 inid 否 2 Intimes 住院次数 int 是 3 Payid 结算次数 int 是 4 Wardid 住院病区 varchar(4) 是 5 timestemp 产生时间 datetime 否 6 Costdate 费用时间 datetime 是 7 Performid 执行序号 int 是 8 Ordercode 项目代码 varchar(6) 是 9 lors 确认标志 smallint 是 10 Amount 冲正数量 numeric(18, 2) 是 11 price 单价 numeric(18, 2) 是 12 Operator 录入人 int 是 13 Itemid 医嘱标识 datetime 否 14 Pay 结算标识 float 是 15 Docnum 住院医生号 varchar(5) 是 16 Performed 执行标志 smallint 是 (12)费用记录表 OrderCost Key: Inid+Itemid+Costdate 序号 字段名 字段含义 数据类型 是否为空 1 Inid 住院号 float 否 2 Wardid 住院病区 varchar(4) 是 3 Intimes 住院次数 int 是 4 Costdate 费用时间 datetime 否 5 Ordercode 项目代码 varchar(6) 是 6 Dose 剂量 numeric(18, 2) 是 7 PTimes 执行次数 numeric(18, 2) 是 8 OrderPrice 单价 numeric(18, 2) 是 9 Lors 长嘱或临嘱 smallint 是 10 Performid 执行序号 int 是 11 Payid 结算次数 int 是 12 Itemid 医嘱产生时间 datetime 否 13 Pay 结算标识 float 是 14 Type 费用类型 smallint 是 15 Docnum 住院医生号 varchar(5) 是 16 Performop 发药人 int 是 17 Performed 发药标志 smallint 是 18 Performtime 发药时间 datetime 是 19 TimesID 用法号 smallint 是 (13)医嘱执行次数表 OrderTimes Key: TimesID 序号 字段名 字段含义 数据类型 是否为空 1 TimesId 次数号 inid 否 2 TimesName 次数名称 varchar(10) 是 3 UnitTimes 单位次数 int 是 4 FactorTimes 时间因子 numeric(18, 4) 是 (14)发药请求表 ReqRec Key: Inid+ReqID 序号 字段名 字段含义 数据类型 是否为空 1 Inid 住院号 inid 否 2 Name 姓名 int 是 3 Bed 床号 int 是 4 Intimes 住院次数 int 是 5 Payid 结算次数 int 是 6 Wardid 住院病区 varchar(4) 是 7 lors 长嘱或临嘱 smallint 是 8 Reqid 医嘱产生时间 datetime 否 9 ReqWard 发药病区 varchar(4) 是 10 Performed 执行标志 smallint 是 11 Accepted 接收标志 smallint 是 (15)发药记录表 ReqRecMX Key: Inid+Itemid+Costdate 序号 字段名 字段含义 数据类型 是否为空 1 Inid 住院号 float 否 2 Wardid 住院病区 varchar(4) 是 3 Intimes 住院次数 int 是 4 Costdate 费用时间 datetime 否 5 Ordercode 项目代码 varchar(6) 是 6 Dose 剂量 numeric(18, 2) 是 7 PTimes 执行次数 numeric(18, 2) 是 8 OrderPrice 单价 numeric(18, 2) 是 9 Lors 长嘱或临嘱 smallint 是 10 Performid 执行序号 int 是 11 Payid 结算次数 int 是 12 Itemid 医嘱产生时间 datetime 否 13 Pay 结算标识 float 是 14 Type 费用类型 smallint 是 15 Docnum 住院医生号 varchar(5) 是 16 Performop 发药人 int 是 17 Performed 发药标志 smallint 是 18 Performtime 发药时间 datetime 是 19 TimesID 用法号 smallint 是 第六章 详细设计 6.1 医嘱录入;

病人医嘱是医院住院管理系统中最重要的输入数据。病人的一切医疗费用记录均由医嘱产生,医疗费用记录除了记录病人的费用外,还记录着住院病区和医生的实际收益和工作量,因此在病人医嘱在病人住院费用计算和科室核算中属于原始数据。

在医院住院信息管理系统中,病人的医嘱分为长期医嘱、临时医嘱和附加治疗项目。长期医嘱主要是那些需要长期执行的医嘱,有开始和停止时间,可以执行多次。临时医嘱主要是那些临时执行的医嘱,只执行一次,只有医嘱的执行时间没有停止时间。附加治疗项目是指那些附带在长期医嘱或临时医嘱的执行过程中执行的治疗项目。例如药物注射治疗的医嘱除了要执行要物治疗外还需要执行附带的注射治疗,在收费中除了要计算药物的费用外还需要计算注射治疗的费用。

录入医嘱的地点一般在住院病区客户端,可以录入长期医嘱和临时医嘱并且可以根据用法情况自动产生附加治疗项目。出入院收费客户端可以作为补充医嘱录入临时医嘱,但不能自动产生附加治疗项目。

医嘱的例如规则包括:
l 只能早于当前时间20小时的医嘱;

l 长期医嘱和临时医嘱在未确认前可以自由修改和删除,确认后不能删除医嘱,长期医嘱只能修改停止时间和停止医嘱,临时在确认后不能作修改,长期医嘱在停止后停止时间也不能再修改;

l 医嘱必须录入有效的治疗项目,中心药房提示缺药的药物也不能输入;

l 医嘱的执行序号用于区别每一组不同的附加治疗项目,同一组执行的医嘱使用相同的序号,分别执行的使用不同的序号。

图6-1医嘱录入的流程图:
在程序中医嘱录入的操作主要由一个TwwClientDataSet对象作为数据源向应用服务器请求数据,一个TwwDBGrid网格对象显示数据,一个TwwDataSource对象建立数据源与数据显示对象的联系。程序中主要通过对这些对象的事件处理程序的编程来实现对医嘱录入操作的控制。

TwwClientDataSet对象的AfterInsert事件处理程序一般负责对自动输入数据字段和默认值字段的数据输入工作如:病人的住院号(inid),住院次数(intimes),医嘱开始执行时间(starttime),住院医生工号(docnum)等。自动输入字段的值输入后不能被修改,如病人住院号、住院次数等,默认值字段如医嘱开始时间、次数、用法等可以由操作员自行修改。下面是长期医嘱的数据访问对象qrylorder的AfterInsert事件处理程序的程序片段:
qrylorder.FieldByName('inid'). asinteger:=inid; qrylorder.FieldByName('intimes'). asinteger:=intimes; qrylorder.FieldByName('payid').asinteger:=payid; qrylorder.FieldByName('wardid'). asstring:=currentward; qrylorder.FieldByName('timestemp'). asdatetime:=time; qrylorder.FieldByName('starttime').asdatetime:=time; qrylorder.FieldByName('docnum').asstring:=docnum; TwwClientDataSet对象的BeforePost事件处理程序实现保存前对输入数据的正确性检查。下面是长期医嘱的数据访问对象qrylorder的BeforePost事件处理程序:
procedure TfrmOrderIn.qryLorderBeforePost(DataSet: TDataSet); begin if (dataset.fieldbyname('starttime').value=0.0) then begin showmessage('必须输入开始日期!'); abort; end; if ((dataset.FieldByName('ordercode').value='') or (Dataset.FieldByName('ordername').value=' ')) then begin showmessage('必须输入有效的治疗项目!'); abort; end; if ((Dataset.FieldByName('ordertimes').value=0)) then begin showmessage('请输入用量!'); abort; end; if ((Dataset.FieldByName('isstop').value=1) and (Dataset.fieldbyname('stoptime').value<dataset.fieldbyname('starttime').value)) then begin showmessage('停止时间必须大于开始时间'); abort; end; if ((Dataset.FieldByName('isstop').value=1) and (Dataset.FieldByName('stoptime').value=99999.0)) then begin showmessage('请输入停止时间!'); abort; end; if (DataSet.FieldByName('dose').value>DataSet.FieldByName('maxamount').value) then begin showmessage('剂量超出允许范围,请改正!') ; abort; end; if (dataset.FieldByName('dose').value=0.0) then begin showmessage('请输入剂量'); abort; end; end; 医嘱内容的自动输入或是否允许输入则是由显示数据的网格对象的事件处理程序实现的。对网格对象的OnCellChanged编程可以通过判别当前字段是否允许修改,然后设定字段的ReadOnly是否为True来实现控制输入的目的。

对OnKeyPress事件处理程序编程可以实现一些自动操作。在事件处理程序中一般是先判断键盘输入参数key的ASCII码值来判段键盘的输入键,然后用网格的SelectedField.name属性来判别当前输入字段名以决定下一步执行哪一段代码。下面是输入嘱中,操作员输入了项目代码后自动填入项目信息的代码:
if key=#13 then begin //if press Enter key //if the field is 'ordercode' if gridLorder.SelectedField.name='qryLorderordercode' then begin if (getitems(qryLorder,gridlorder.selectedfield.value,1))=1 then begin gridlorder.RefreshDisplay; gridlorder.SelectedIndex:=5; end else gridlorder.SelectedIndex:=1; end; 下一条判定字段名称的代码 end; 在代码中如果用户按Enter键并且当前字段为ordercode则调用自动填入项目信息的getitems函数。调用成功后刷新显示,用设定SelectedIndex属性的值来控制光标停留在下一个需要录入的字段。

对OnKeyDown事件处理函数的编程可以在输入中设定热键,在输入中按F2键就打开项目代码模糊查询窗口的代码如下:
procedure TfrmOrderIn.gridLorderKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if key=vk_F2 then begin qryLorder.Edit; if ((gridlorder.SelectedField.name='qryLorderordercode') and (gridLorder.SelectedField.ReadOnly=false)) then begin qryLorder.Edit; //执行模糊查询 qryLorder.FieldByName('ordercode').value:=lookupcode(qrylorder); end; end; end; 在所有输入操作完成后还需要把新修改的数据保存到数据库中。根据Delphi三层结构的技术原理,客户端TwwClientDataSet对象的数据仅保存在客户端计算机的内存中,客户端对数据的修改不会自动保存到数据库中,需要调用TwwClientDataSet的ApplyUpdate方法把数据提交回应用服务器,再由应用服务器把数据保存到数据库中。

6.2产生发药记录 图6-2 发药流程图 录入后的医嘱需要经过发药操作才会产生住院费用。非药物治疗的医嘱项目经过产生发药记录操作后发送到出入院数据库的tmpOrderCost表中就可以直接产生费用,药物治疗的医嘱项目还需要经过中心药房的确认发药后由出入院收费系统接收后才会产生费用。每条医嘱一天只产生发药记录一次,一次产生一条发药记录,发药成功后最后执行时间写入医嘱记录表的LastPerform字段中,新录入医嘱的LastPerform值为’1899-12-30’。

执行产生发药记录的代码在应用服务器运行,病区发药在病区应用服务器运行,出入院收费处补充发药在出入院收费应用服务器(只能为单个病人补充发药)运行。按发药的规模可以分成病区发药(调用WPerformorder过程)和单个病人发药(调用PPerformOrder过程),但流程基本相同。

扫描需要发药的医嘱然后产生发药记录和发药请求的工作由PerformOrder过程来完成。PerformOrder只完成单个病人医嘱的发药操作,单个病人发药的PPerformOrder过程只调用PerformOrder一次,病区发药WPerformorder过程则要为病区的每一位病人调用PerformOrder一次。

确定需要发药医嘱主要的参考字段有:LastPerform,sure,isstop,stoptime,由于临时医嘱只执行一次,所以判定表达式比较简单:sure=1 and LastPerform=’1899-12-30’;
但由于长期医嘱涉及到医嘱的停止时间问题所以判定表达式比较复杂:
sure=1 and (a.LastPerform<=:PTime and isstop=0) or (isstop=1 and stoptime>=:PTime and a.lastperform<=:PTime) 在产生发药记录时除了需要知道剂量外还要知道执行的次数,从数小时执行一次到数天执行一次不等,为了能准确计算医嘱的执行次数需要在医嘱次数表中设置UnitTimes和FactorTimes两个字段分别表示在每次发药中的执行次数和发药时间换算因子。在Delphi中时间以浮点数表示,1表示1天,1/24表示1小时,如此类推。因此,以(本次发药的最后执行时间-上次发药的最后执行时间)*FactorTimes即可得出本次发药的单位执行了次数,在乘以UnitTimes即可得到医嘱在本次发药的实际执行次数。

在长期医嘱产生发药记录时需要先用NeedCreatRec函数判定今天是否要执行医嘱然后再产生发药记录,如果(本次发药的最后执行时间-上次发药的最后执行时间)*FactorTimes小于1则NeedCreatRec返回0表示医嘱不用执行。

函数CreatReqRecMX用于产生发药记录并把发药医嘱的LastPerform字段的值改为次日的9点。对于治疗项目的类型不同函数内部有不同的处理,对于类型码为1的项目由于是药品类型需要经中心药房确认发药所以价格字段OrderPrice的值为0,其他类型的项目由于可以直接产生费用所以写入项目的价格。CreatReqRecMX的返回值为项目类型码,如果返回值为药品类型,则PerformOrder还需要产生一条发药请求记录。

在产生完发药记录后还需要调用CreatAddCost一次以产生附加费用记录。

发药记录在产生后还要通过发送操作才能完成发药过程。住院病区应用服务器在完成产生发药记录后所有药物和非药物治疗的发药记录的Performed字段值为0,表示为新生成未传送状态。非药物治疗项目的发药记录直接发送到出入院数据库的tmpOrderCost表并且Performed字段值改为2即可产生费用;
药物治疗项目的发药记录则需要同时发往中心药房数据库的tmpReqRecMX表和出入院数据库的tmpOrderCost表并且Performed字段值改为1,表示完成发送,等待中心药房确认发药后tmpOrderCost表中相应发药记录的Performed字段值为2才会产生费用。本次发药所产生的发药请求会一同发送到中心药房数据库的tmpReqRec表中,Performed字段值改为1,Accepted字段值为0。

出入院收费应用服务器由于发药记录直接产生到tmpOrderCost表中所以发送比较简单,只需把药物治疗项目的发药记录和发药请求发送到中心药房数据库相应的表中即可。

6.3中心药房发药;

中心药房发药系统的主要工作是对各病区药品治疗的发药记录作发药确认处理,以作为药品消耗数据。各科室产生的发药记录和发药请求分别存放在中心药房数据库的tmpReqRecMX表和tmpReqRec表中,中心药房发药的处理就是根据发药请求搜索对应的发药记录做发药处理。

发药的操作由中心药房客户端触发,中心药房客户端操作员利用客户端浏览发药请求信息,决定是否发药,然后触发客户端的发药过程。客户端的发药过程根据操作员对发药记录所设定发药选择产生发药信息数组作为Variant类型的参数发调用中心药房应用服务器的发药服务 PerformReq触发应用程序服务器的发药线程PerformMedReq。

每次发药以一个病人的一条发药请求记录为单位。发药处理的流程是:搜索发药请求所对应的发药记录,查找药品的价格,更新发药记录的发药标记和价格,对每条发药记录都要扣减药品库存表中对应药品的库存,所有发药记录都完成后要给发药请求作发药标记。每次发药都由一个单独的事务控制,以保证操作的完整性。在发药前发药记录和发药请求记录的Performed字段的值都为1,完成后Performed字段的值都为2。

由于中心药房应用服务器同时为多个客户端服务,多个客户端可能同时对某一个药品作发药操作,为了防止并发处理引起的“脏数据”的发生,在管理发药线程时应用程序服务器使用了临界区机制,保证同一时可只有一条发药线程在运行。

在线程的执行函数Execute的开头调用windows API函数EnterCriticalSection使本线程进入临界区,在线程的结束处理函数中调用windows API函数LeaveCriticalSection离开临界区以使其他线程可以进入临界区。下面是线程PerformMedReq执行发药的代码:
procedure PerformMedReq.Execute; var i:integer; ok:Variant; begin //进入临界区 EnterCriticalSection(cs); dm.IsPerformed.close; dm.IsPerformed.ParamByName('inid').asinteger:=inid; dm.IsPerformed.ParamByName('reqid').asdatetime:=reqid; dm.IsPerformed.open; if (dm.IsPerformed.FieldByName('performed').asinteger=1) then try dm.db2.StartTransaction; for i:=VarArrayLowBound(data,1) to VarArrayHighBound(data,1) do begin ok:=data[i]; dm.upReqMX.close; //查找药品价格 dm.qryPrice.close; dm.qryPrice.ParamByName('ordercode').asstring:=ok[5]; dm.qryPrice.open; if not dm.qryPrice.IsEmpty then dm.upReqMX.ParamByName('price').asfloat :=dm.qryPrice.fieldbyname('orderprice').asfloat else dm.upReqMX.ParamByName('price').asfloat:=0; dm.qryPrice.close; //更新发药记录 dm.upReqMX.ParamByName('performed').asinteger:=trunc(ok[4]); dm.upReqMX.ParamByName('op').asinteger:=op; dm.upReqMX.ParamByName('inid').asinteger:=inid; dm.upReqMX.ParamByName('itemid').asdatetime:=ok[0]; dm.upReqMX.ParamByName('costdate').asdatetime:=ok[1]; dm.upReqMX.ParamByName('reqid').asdatetime:=reqid; dm.upReqMX.ParamByName('type').asinteger:=trunc(ok[3]); dm.upReqMX.ExecSQL; dm.upReqMX.close; //更新库存量 dm.upMedAmount.close; dm.upMedAmount.ParamByName('ordercode').asstring:=ok[5]; dm.upMedAmount.ParamByName('dose').asfloat:=ok[2]; dm.upMedAmount.ExecSQL; dm.upMedAmount.close; end; //更新发药请求 dm.upReqRec.close; dm.upReqRec.ParamByName('inid').asinteger:=inid; dm.upReqRec.ParamByName('reqid').asdatetime:=reqid; dm.upReqRec.ExecSQL; dm.upReqRec.close; dm.db2.Commit; except dm.db2.Rollback; raise; end; end; 在发药请求完成发药后发药请求记录Accepted字段的值为0,开始等待出入院应用程序服务器接收发药信息。

6.4住院费用结算;

出入院应用程序服务器中设置了一个Ttimer对象,用于每隔一分钟启动ReciveRec线程一次,从中心药房数据库接收发药信息。ReciveRec线程的先查询中心药房发药系统的接口tmpReqRec表中完成发药但未被出入院收费系统接收的发药请求记录,查询的SQL语句是:
select inid,intimes,payid,wardid,lors,reqid,reqward from tmpReqRec where accepted=0 and performed=2 再为每条完成发药的发药请求查询在tmpReqRecMX表中的发药记录,再用Update语句更新出入院数据库tmpOrdercost表中对应记录(产生发药信息时保存在tmpOrdercost表中)的Orderprice和Performed字段,最后把发药请求记录的Accepted字段值更新为1,即可完成对一条发药记录的接收工作。

为新cepteddest接收由于对病人补充发药的处理也会启动ReciveRec线程一次,为了防止重复接收所以ReciveRec线程也会采用和中心药房发药线程PerformMedReq一样的临界区机制,保证同一时刻只有一条ReciveRec线程在运行。

病人住院费用的计算由出入院应用程序服务器的CountPatientFee方法完成,CountPatientFee由出入院客户端调用,把未结的费用记录按收费分类汇总、合计,再统计未结的住院押金,计算出病人的结余金额:
病人的结余金额=未结住院押金-未结费用总额 所有的费用信息保存在一个数组中,以OleVariant类型返回给客户端。

查询病人费用分类汇总的SQL查询语句:
select a.IncomeType,isnull(c1,0) as c1 from IncomeType a left join (select c.IncomeType as i1,sum(b.dose*b.ptimes*b.orderprice) as c1 from ordercode c,tmpordercost b where c.ordercode=b.ordercode and inid=:inid and intimes=:intimes and costdate between :d1 and :d2 and pay=0 and performed=2 group by c.IncomeType) as cost on a.IncomeType=cost.i1 order by a.IncomeType 出入院客户端在病人费用结算操作中的作用是为CountPatientFee提供查询参数,病人的住院号和住院次数由病人资料提供,关键是设定结算费用起止日期。客户端设定费用结算时间范围的方式有三种:
默认为出院结算方式,系统会统计病人在tmpOrderCost表中未结算费用记录的最早和最迟时间,然后把操作界面中设定结算时间的DataTimePicker控件的值设定为这两个时间。CountPatientFee会统计病人所有未结费用。

客户端程序会在网格控件中显示病人每段未结算费用的起止时间,操作员可以用鼠标右键打开快捷菜单快速设定结算的起止时间。

在DataTimePicker控件中自由设定结算的起止时间。

后两种方法要在出院结算模式无效的情况下设定才有效。

在出院结算模式无效的情况下也可以自由选择结算的住院押金。客户端在调用完CountPatientFee后,还要统计操作窗口中选择结算的押金金额作为本次结算的未结住院押金金额。

在完成统计费用后可以进入收款操作。收款方式主要是现金收款或通过ICCard收款,两者之和为病人补交款总金额,如果补交款总额小于应补交金额则为交款不足,本次结算作立欠处理。

完成结算的标志是打印收款收据,在打印收据前要做一系列保存费用处理,这些处理包括保存结算信息,收据信息,现金收款信息,ICCard收款信息,把参加结算的费用记录打上结算标识后从tmpOrderCost保存到OrderCost表中,参加结算的住院押金记录也要打上结算标识。

每一次结算操作都有一个唯一的结算标识,结算标识字段Pay存在于与结算有关的Paydata,FP,CashPay,ICCard,OrderCost表中,Pay是一个浮点数,由病人的住院号和结算时间构成:
pay=strtofloat(inttostr(inid)+inttostr(trunc(timestemp*1000000))) 在现实情况下一个病人不可能在同一时间结算两次,所以采用此算法可以保证结算标识的唯一。在完成结算后可以通过调用应用服务器SetPayDelete方法把费用记录和押金记录返回到未结算状态,这次结算在Paydata表中的记录被打上作废标志State=2。

图6-3 住院费用结算流程图费用CardmeCost 6.5打印费用清单 打印费用清单主要是要查询费用记录表OrderCost和tmpOrderCost中符合时间范围的费用记录按费用类型和项目代码分类汇总,然后以报表形式打印出来。该查询的SQL:
select a.inid, a.ordercode, b.ordername, b.specification, b.orderunit, sum(a.amount) as tamount, round(sum(a.cost),2) as tcost, c.incomename from (select inid, intimes , ordercode , sum(dose*ptimes) amount, sum(dose*ptimes*orderprice) as cost from tmpordercost where inid=:inid and pay=0 and performed=2 and costdate between :day1 and :day2 group by inid,intimes,ordercode union all select inid , intimes , ordercode , sum(dose*ptimes) amount, sum(dose*ptimes*orderprice) as cost from ordercost where inid=:inid and costdate between :day1 and :day2 group by inid,intimes,ordercode) as a left join (select ordercode,ordername,specification,orderunit,incometype from ordercode) as b on b.ordercode=a.ordercode left join incometype as c on c.incometype=b.incometype group by inid,a.ordercode,ordername,specification,orderunit,incomename 第七章 测试及性能分析 7.1 功能测试 功能测试的主要内容是按实际操作的数据向系统的各个功能模块输入数据,检测输出结果是否符合预期要求。

7.2 系统测试 在对各个模块的测试完成后对整个系统作一个完整的测试,以检验各模块在联合运行时运行结果是否符合预期要求。

7.3 性能分析 三层分布式系统的特点就是把数据访问层和企业逻辑层分开,把运行企业逻辑的任务分布到各应用程序服务器上,数据库服务器可以专职用于访问数据。与两层系统相比由于数据库平台和企业逻辑可以在不同的计算机上运行,所以可以大大地减轻数据库服务器的负担,系统也具有很强的延展性,使系统在处理数据量不断增大的情况下对系统的处理速度不致影响太大。

虽然在三层结构下客户端直接访问数据时需要经过应用程序服务器的转换,速度可能不及两层结构,但分布式处理和容易维护方面的优势完全可以抵消这一缺点。通过升级应用程序服务器硬件和优化应用程序服务器软件完全可以加快数据的访问速度。

在实际测试中,打开病人的医嘱大概需要1~2秒,病区为一名病人发药需要1~2秒,计算一个病人的住院费用小于1秒。

结束语 本篇论文主要阐述了一个医院住院信息管理系统的开发过程,从需求的提出到分析、,析1 dderCost 总体设计、详细设计到测试。虽然由于时间不足的问题不能对整个系统作一个完整论述,但是基本能对本次开发活动的核心技术和设计思想有较完整的描述。

本人在医院住院信息管理系统开发工作中担任了需求分析,系统总体设计、数据结构设计、详细设计、编码、测试等工作。虽然开发的工作量比较大,时间也比较紧迫,但我还是克服了困难完成了医院住院信息管理系统的基本功能模块的开发工作。

在开发工作中应用了UML作为需求分析工具,构建系统使用了三层结构,比以前采用的结构化分析和两层结构在技术上提高了一个层次。虽然对新技术的理解和应用还不够全面,但毕竟是迈出了重要的一步。本次开发工作为以后系统的继续完善和其他系统开发积累宝贵的经验。

本次开发的医院信息管理系统只是一个雏形,很多地方还有不完善的地方需要改进,经总结有下面几点:
(1)
对面向对象的软件工程和UML技术使用还不够完整。仅在需求分析阶段应用,在总体设计和详细设计阶段由于时间和对技术的掌握等原因还是采用了结构化开发技术。

(2)
对三层技术的应用还不够全面。仅使用了三层技术的基本技术,三层技术的其他强大功能如负载平衡技术、容错技术,连接池、对象池等技术基本没有应用。

(3)
由于开发时间的关系系统只完成了出入院收费、病区医嘱录入和发药,中心药房发药等基本功能,系统维护、数据备份和恢复等功能没有完成。由于系统数据分散在若干个数据库服务器中,对数据的备份比较复杂,可以使用SQL Server的数据复制功能,建立接收各数据库数据的订阅服务器,定时从各服务器复制数据。

(4)
系统的功能还可以进一步扩展。可以扩展病区应用服务器的功能,使它变成整个病区的数据服务中心,不但为病区管理客户端服务,还可以为医生工作站服务。病人的医嘱可以以XML文件的形式输出,方便与其他系统交换数据。增加统计报表的种类,可以利用医院住院病区管理系统产生和保存的数据为完善医院的科室核算工作和管理工作服务。

(5)
住院病区客户端还不能够自由选择连接的住院病区应用程序服务器。主要是为了方便手术室录入手术医嘱、出入院收费处录入记帐医嘱。由于病人的医嘱在办理结帐前医嘱数据保存在住院病区的数据库中,所以医嘱在手术室或出入院收费处录入时需要根据病人所在的住院病区选择客户端连接的应用程序服务器。解决方法是为每台病区服务器配置一个.INI文件,在.INI文件中保存客户端应用程序可以连接的住院病区应用程序服务器的信息,让操作员在登陆时选择。另外,还可以结合操作员的操作权限,只让手术室和出入院收费处的操作员可以自由选择登录的病区应用程序服务器。

(6)药品管理方面只完成了发药扣减中心药房库存的功能,盘点、有效期管理,药库管理等功能没有完成。

致谢 非常感谢我的课题指导老师XX老师在这次开发中对我的指导和支持,以及佛山电大科研处的各位老师对我的指导,第5组的同学给我的帮助,佛山市第三人民医院的各位领导、财务科、住院病区四科、药剂科中心药房、西药库的同志们给本课题提供的极其有用的资料。最后特别感谢我的妈妈,没有她的后勤支援我是无法完成这次开发任务的。

参考文献 [1] B.Bruegge,A.H.Dutoit,面向对象软件工程,清华大学出版社,2002 [2] Craig Larman,UML和模式应用-面向对象分析和设计导论,机械工业出版社,2002 [3]Grady Booch,James Rumbaugh,Ivar Jacobson,UML用户指南,机械工业出版社,2002 [4] Grady Booch,James Rumbaugh,Ivar Jacobson,UML参考手册,机械工业出版社,2002 [5] 郑人杰,实用软件工程,清华大学出版社,2000 [6] Kent Reisdorph,轻松掌握Delphi 4,电子工业出版社,1999 [7] 李维,Delphi 5 分布式多层应用系统篇,2000 [8] 李存斌,Delphi深度编程及其应用项目开发,中国水利出版社,2002 [9] Borland,Delhi 5 联机帮助文档,Inprise,1999 [10] Microsoft,Microsoft SQL Server 2000 联机帮助文档,2000 [11] 赵起超,医院信息管理系统,哈尔滨工业大学出版社,2001phi 5 dorph,

推荐访问: