跳转至

实验室信息系统(LIS)集成

LIS系统概述

实验室信息系统(Laboratory Information System, LIS)是用于管理医学实验室工作流程、样本追踪、结果报告和质量控制的综合信息系统。

系统架构

典型LIS架构

class LISArchitecture:
    """LIS系统架构"""

    def __init__(self):
        self.components = {
            "order_management": OrderManagementModule(),
            "sample_tracking": SampleTrackingModule(),
            "instrument_interface": InstrumentInterfaceModule(),
            "result_management": ResultManagementModule(),
            "quality_control": QualityControlModule(),
            "reporting": ReportingModule(),
            "billing": BillingModule(),
            "inventory": InventoryModule()
        }

    def process_workflow(self, order):
        """处理工作流程"""
        # 1. 接收医嘱
        order_id = self.components["order_management"].receive_order(order)

        # 2. 样本采集和追踪
        sample = self.components["sample_tracking"].register_sample(order_id)

        # 3. 分配到仪器
        instrument = self.components["instrument_interface"].assign_instrument(sample)

        # 4. 接收结果
        result = self.components["result_management"].receive_result(sample)

        # 5. 质控验证
        if self.components["quality_control"].validate(result):
            # 6. 生成报告
            report = self.components["reporting"].generate_report(result)
            return report
        else:
            return self.handle_qc_failure(result)

接口标准

1. HL7接口

HL7 v2.x消息

class HL7Interface:
    """HL7接口实现"""

    def __init__(self):
        self.message_types = {
            "ORM": "医嘱消息",
            "ORU": "观察结果",
            "QRY": "查询消息",
            "ACK": "确认消息"
        }

    def parse_orm_message(self, hl7_message):
        """解析医嘱消息(ORM^O01)"""
        message = hl7.parse(hl7_message)

        # 提取患者信息(PID段)
        patient_info = {
            "patient_id": message.segment("PID")[3][0],
            "patient_name": message.segment("PID")[5][0],
            "date_of_birth": message.segment("PID")[7][0],
            "gender": message.segment("PID")[8][0]
        }

        # 提取医嘱信息(ORC段)
        order_info = {
            "order_control": message.segment("ORC")[1][0],
            "placer_order_number": message.segment("ORC")[2][0],
            "order_status": message.segment("ORC")[5][0]
        }

        # 提取检验项目(OBR段)
        test_info = {
            "set_id": message.segment("OBR")[1][0],
            "placer_order_number": message.segment("OBR")[2][0],
            "universal_service_id": message.segment("OBR")[4][0],
            "observation_datetime": message.segment("OBR")[7][0],
            "specimen_source": message.segment("OBR")[15][0]
        }

        return LabOrder(patient_info, order_info, test_info)

    def create_oru_message(self, test_result):
        """创建观察结果消息(ORU^R01)"""
        message = hl7.Message("ORU", "R01")

        # MSH - 消息头
        message.add_segment("MSH", [
            "|", "^~\\&",
            "LIS_SYSTEM", "LABORATORY",
            "HIS_SYSTEM", "HOSPITAL",
            datetime.now().strftime("%Y%m%d%H%M%S"),
            "",
            "ORU^R01^ORU_R01",
            self.generate_message_control_id(),
            "P",  # 生产环境
            "2.5.1",
            "",
            "",
            "",
            "UNICODE UTF-8"
        ])

        # PID - 患者识别
        message.add_segment("PID", [
            "1",  # Set ID
            "",   # 患者ID(外部)
            test_result.patient_id,  # 患者ID(内部)
            "",   # 备用患者ID
            test_result.patient_name,  # 患者姓名
            "",   # 母亲姓名
            test_result.date_of_birth,  # 出生日期
            test_result.gender,  # 性别
            "",   # 患者别名
            "",   # 种族
            test_result.address,  # 地址
            "",   # 县代码
            test_result.phone,  # 电话
            "",   # 工作电话
            "",   # 主要语言
            "",   # 婚姻状况
            "",   # 宗教
            "",   # 患者账号
            "",   # SSN
            "",   # 驾照号
        ])

        # PV1 - 患者就诊
        message.add_segment("PV1", [
            "1",  # Set ID
            test_result.patient_class,  # 患者类别(I=住院,O=门诊)
            test_result.assigned_location,  # 分配位置
            "",   # 入院类型
            "",   # 预约ID
            "",   # 先前位置
            test_result.attending_doctor,  # 主治医生
            "",   # 转诊医生
            "",   # 会诊医生
            "",   # 医院服务
            "",   # 临时位置
            "",   # 预约类型
            "",   # 入院ID
            "",   # 入院来源
            "",   # 救护车状态
            "",   # VIP指示器
            "",   # 主治医生
            "",   # 患者类型
            test_result.visit_number,  # 就诊号
            "",   # 财务类别
            "",   # 收费价格指示器
            "",   # 礼貌代码
            "",   # 信用评级
            "",   # 合同代码
            "",   # 合同生效日期
            "",   # 合同金额
            "",   # 合同期限
            "",   # 利息代码
            "",   # 转账到坏账代码
            "",   # 转账到坏账日期
            "",   # 坏账机构代码
            "",   # 坏账恢复金额
            "",   # 删除账户指示器
            "",   # 删除账户日期
            "",   # 出院处置
            "",   # 出院到位置
            "",   # 饮食类型
            "",   # 服务机构
            "",   # 床位状态
            "",   # 账户状态
            "",   # 待定位置
            "",   # 先前临时位置
            test_result.admission_datetime,  # 入院日期时间
            "",   # 出院日期时间
        ])

        # ORC - 通用医嘱段
        message.add_segment("ORC", [
            "RE",  # 医嘱控制(RE=观察结果报告)
            test_result.placer_order_number,  # 申请方医嘱号
            test_result.filler_order_number,  # 执行方医嘱号
            "",   # 申请方组号
            "",   # 医嘱状态
            "",   # 响应标志
            "",   # 数量/时间
            "",   # 父医嘱
            test_result.transaction_datetime,  # 事务日期时间
            "",   # 录入者
            "",   # 验证者
            test_result.ordering_provider,  # 医嘱提供者
            "",   # 录入者位置
            "",   # 回调电话号码
            test_result.order_effective_datetime,  # 医嘱生效日期时间
            "",   # 医嘱控制代码原因
        ])

        # OBR - 观察请求段
        message.add_segment("OBR", [
            "1",  # Set ID
            test_result.placer_order_number,  # 申请方医嘱号
            test_result.filler_order_number,  # 执行方医嘱号
            test_result.universal_service_id,  # 通用服务ID
            "",   # 优先级
            "",   # 请求日期时间
            test_result.observation_datetime,  # 观察日期时间
            test_result.observation_end_datetime,  # 观察结束日期时间
            "",   # 采集量
            "",   # 采集者ID
            "",   # 标本操作代码
            "",   # 危险代码
            "",   # 相关临床信息
            "",   # 标本接收日期时间
            test_result.specimen_source,  # 标本来源
            test_result.ordering_provider,  # 医嘱提供者
            "",   # 医嘱回调电话号码
            "",   # 申请方字段1
            "",   # 申请方字段2
            "",   # 执行方字段1
            "",   # 执行方字段2
            test_result.results_rpt_status_chng_datetime,  # 结果报告状态改变日期时间
            "",   # 收费到实践
            "",   # 诊断服务段ID
            test_result.result_status,  # 结果状态(F=最终,P=初步)
            "",   # 父结果
            "",   # 数量/时间
            "",   # 结果副本
            "",   # 父号
            "",   # 运输方式
            "",   # 结果原因
            "",   # 主结果解释者
            "",   # 助理结果解释者
            "",   # 技术员
            "",   # 转录员
            "",   # 计划日期时间
        ])

        # OBX - 观察结果段(可以有多个)
        for idx, observation in enumerate(test_result.observations, 1):
            message.add_segment("OBX", [
                str(idx),  # Set ID
                observation.value_type,  # 值类型(NM=数值,ST=字符串,CE=编码条目)
                observation.observation_id,  # 观察标识符
                observation.observation_sub_id,  # 观察子ID
                observation.observation_value,  # 观察值
                observation.units,  # 单位
                observation.reference_range,  # 参考范围
                observation.abnormal_flags,  # 异常标志(N=正常,H=高,L=低,HH=危急高,LL=危急低)
                "",   # 概率
                "",   # 异常测试性质
                observation.observation_result_status,  # 观察结果状态(F=最终)
                "",   # 生效日期
                "",   # 用户定义访问检查
                observation.datetime_of_observation,  # 观察日期时间
                "",   # 生产者ID
                "",   # 负责观察者
                "",   # 观察方法
            ])

        # NTE - 注释和评论段(可选)
        if test_result.comments:
            for idx, comment in enumerate(test_result.comments, 1):
                message.add_segment("NTE", [
                    str(idx),  # Set ID
                    "L",  # 注释来源(L=实验室)
                    comment,  # 注释
                ])

        return message.to_string()

    def send_acknowledgment(self, original_message, status="AA"):
        """发送确认消息(ACK)"""
        ack = hl7.Message("ACK")

        # MSH段
        ack.add_segment("MSH", [
            "|", "^~\\&",
            "LIS_SYSTEM", "LABORATORY",
            original_message.sending_application,
            original_message.sending_facility,
            datetime.now().strftime("%Y%m%d%H%M%S"),
            "",
            "ACK",
            self.generate_message_control_id(),
            "P",
            "2.5.1"
        ])

        # MSA段 - 消息确认
        ack.add_segment("MSA", [
            status,  # 确认代码(AA=应用接受,AE=应用错误,AR=应用拒绝)
            original_message.message_control_id,  # 消息控制ID
            "Message received successfully" if status == "AA" else "Error processing message"
        ])

        return ack.to_string()

2. ASTM接口

ASTM E1394标准

class ASTMInterface:
    """ASTM接口实现"""

    def __init__(self):
        self.STX = '\x02'  # 开始字符
        self.ETX = '\x03'  # 结束字符
        self.EOT = '\x04'  # 传输结束
        self.ENQ = '\x05'  # 查询
        self.ACK = '\x06'  # 确认
        self.NAK = '\x15'  # 否定确认
        self.LF = '\x0A'   # 换行
        self.CR = '\x0D'   # 回车

    def create_result_message(self, test_result):
        """创建结果消息"""
        frames = []

        # Header记录
        header = self.create_header_record()
        frames.append(header)

        # Patient记录
        patient = self.create_patient_record(test_result.patient)
        frames.append(patient)

        # Order记录
        order = self.create_order_record(test_result.order)
        frames.append(order)

        # Result记录
        for result in test_result.results:
            result_record = self.create_result_record(result)
            frames.append(result_record)

        # Terminator记录
        terminator = self.create_terminator_record()
        frames.append(terminator)

        return self.build_message(frames)

    def create_header_record(self):
        """创建Header记录(H记录)"""
        fields = [
            "H",  # 记录类型
            "\\^&",  # 分隔符定义
            "",  # 消息控制ID
            "",  # 访问密码
            "LIS_SYSTEM",  # 发送者名称或ID
            "",  # 发送者街道地址
            "",  # 保留字段
            "",  # 发送者电话号码
            "",  # 发送者特征
            "",  # 接收者ID
            "",  # 注释或特殊说明
            "",  # 处理ID
            "ASTM-E1394",  # 版本号
            datetime.now().strftime("%Y%m%d%H%M%S")  # 时间戳
        ]
        return "|".join(fields)

    def create_patient_record(self, patient):
        """创建Patient记录(P记录)"""
        fields = [
            "P",  # 记录类型
            "1",  # 序列号
            patient.patient_id,  # 患者ID
            "",  # 实验室分配的患者ID
            "",  # 患者ID号3
            patient.patient_name,  # 患者姓名
            "",  # 母亲姓名
            patient.date_of_birth,  # 出生日期
            patient.gender,  # 性别
            "",  # 患者种族
            patient.address,  # 患者地址
            "",  # 保留字段
            patient.phone,  # 患者电话号码
            patient.attending_physician,  # 主治医生
            "",  # 特殊字段1
            "",  # 特殊字段2
            "",  # 患者身高
            "",  # 患者体重
            "",  # 患者诊断
            "",  # 患者活动药物
            "",  # 患者饮食
            "",  # 实践字段1
            "",  # 实践字段2
            "",  # 入院和出院日期
            "",  # 入院状态
            "",  # 位置
            "",  # 备用诊断代码和分类
            "",  # 患者宗教
            "",  # 婚姻状况
            "",  # 隔离状态
            "",  # 语言
            "",  # 医院服务
            "",  # 医院机构
            "",  # 剂量类别
        ]
        return "|".join(fields)

    def create_order_record(self, order):
        """创建Order记录(O记录)"""
        fields = [
            "O",  # 记录类型
            "1",  # 序列号
            order.specimen_id,  # 标本ID
            "",  # 仪器标本ID
            order.universal_test_id,  # 通用测试ID
            order.priority,  # 优先级
            order.requested_datetime,  # 请求日期时间
            order.collection_datetime,  # 采集日期时间
            "",  # 采集结束时间
            "",  # 采集量
            "",  # 采集者ID
            "",  # 操作代码
            "",  # 危险代码
            "",  # 相关临床信息
            order.received_datetime,  # 标本接收日期时间
            order.specimen_descriptor,  # 标本描述符
            order.ordering_physician,  # 医嘱医生
            "",  # 医生电话号码
            "",  # 用户字段1
            "",  # 用户字段2
            "",  # 实验室字段1
            "",  # 实验室字段2
            "",  # 报告日期时间
            "",  # 仪器收费到计算机系统
            "",  # 仪器段ID
            order.report_type,  # 报告类型
            "",  # 保留字段
            "",  # 位置或病房的标本
            "",  # 感染标志
            "",  # 标本服务
            "",  # 标本机构
        ]
        return "|".join(fields)

    def create_result_record(self, result):
        """创建Result记录(R记录)"""
        fields = [
            "R",  # 记录类型
            str(result.sequence_number),  # 序列号
            result.universal_test_id,  # 通用测试ID
            result.data_measurement,  # 数据或测量值
            result.units,  # 单位
            result.reference_ranges,  # 参考范围
            result.abnormal_flag,  # 异常标志
            "",  # 结果异常性质
            result.result_status,  # 结果状态
            "",  # 日期更改仪器规范值
            "",  # 操作员识别
            "",  # 日期时间测试开始
            result.datetime_test_completed,  # 日期时间测试完成
            result.instrument_id,  # 仪器识别
        ]
        return "|".join(fields)

    def create_terminator_record(self):
        """创建Terminator记录(L记录)"""
        fields = [
            "L",  # 记录类型
            "1",  # 序列号
            "N"   # 终止代码(N=正常终止)
        ]
        return "|".join(fields)

    def build_message(self, frames):
        """构建完整消息"""
        message_frames = []

        for idx, frame in enumerate(frames, 1):
            # 计算校验和
            checksum = self.calculate_checksum(frame)

            # 构建帧
            frame_number = str(idx % 8)  # 帧号0-7循环
            complete_frame = f"{self.STX}{frame_number}{frame}{self.CR}{self.ETX}{checksum}{self.CR}{self.LF}"
            message_frames.append(complete_frame)

        # 添加EOT
        message_frames.append(self.EOT)

        return "".join(message_frames)

    def calculate_checksum(self, data):
        """计算校验和"""
        checksum = sum(ord(c) for c in data) % 256
        return f"{checksum:02X}"

3. FHIR接口

现代RESTful API

class FHIRInterface:
    """FHIR接口实现"""

    def __init__(self, base_url):
        self.base_url = base_url
        self.version = "R4"

    def create_diagnostic_report(self, test_result):
        """创建诊断报告资源"""
        report = {
            "resourceType": "DiagnosticReport",
            "id": test_result.report_id,
            "meta": {
                "versionId": "1",
                "lastUpdated": datetime.now().isoformat()
            },
            "status": "final",  # registered | partial | preliminary | final
            "category": [{
                "coding": [{
                    "system": "http://terminology.hl7.org/CodeSystem/v2-0074",
                    "code": "LAB",
                    "display": "Laboratory"
                }]
            }],
            "code": {
                "coding": [{
                    "system": "http://loinc.org",
                    "code": test_result.test_code,
                    "display": test_result.test_name
                }]
            },
            "subject": {
                "reference": f"Patient/{test_result.patient_id}"
            },
            "effectiveDateTime": test_result.effective_datetime,
            "issued": test_result.issued_datetime,
            "performer": [{
                "reference": f"Organization/{test_result.lab_id}",
                "display": test_result.lab_name
            }],
            "result": [
                {
                    "reference": f"Observation/{obs.id}"
                }
                for obs in test_result.observations
            ],
            "conclusion": test_result.conclusion
        }

        return report

    def create_observation(self, observation):
        """创建观察资源"""
        obs = {
            "resourceType": "Observation",
            "id": observation.id,
            "status": "final",
            "category": [{
                "coding": [{
                    "system": "http://terminology.hl7.org/CodeSystem/observation-category",
                    "code": "laboratory",
                    "display": "Laboratory"
                }]
            }],
            "code": {
                "coding": [{
                    "system": "http://loinc.org",
                    "code": observation.loinc_code,
                    "display": observation.test_name
                }]
            },
            "subject": {
                "reference": f"Patient/{observation.patient_id}"
            },
            "effectiveDateTime": observation.effective_datetime,
            "issued": observation.issued_datetime,
            "valueQuantity": {
                "value": observation.value,
                "unit": observation.unit,
                "system": "http://unitsofmeasure.org",
                "code": observation.ucum_code
            },
            "referenceRange": [{
                "low": {
                    "value": observation.ref_range_low,
                    "unit": observation.unit
                },
                "high": {
                    "value": observation.ref_range_high,
                    "unit": observation.unit
                }
            }],
            "interpretation": [{
                "coding": [{
                    "system": "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation",
                    "code": observation.interpretation_code,  # N, H, L, HH, LL
                    "display": observation.interpretation_display
                }]
            }]
        }

        return obs

    def submit_report(self, diagnostic_report):
        """提交诊断报告"""
        response = requests.post(
            f"{self.base_url}/DiagnosticReport",
            json=diagnostic_report,
            headers={
                "Content-Type": "application/fhir+json",
                "Accept": "application/fhir+json"
            }
        )

        if response.status_code == 201:
            return response.json()
        else:
            raise FHIRError(f"提交失败: {response.text}")

样本追踪

条形码系统

class SampleTrackingSystem:
    """样本追踪系统"""

    def __init__(self):
        self.barcode_generator = BarcodeGenerator()
        self.tracking_database = TrackingDatabase()

    def register_sample(self, sample_info):
        """注册样本"""
        # 生成唯一样本ID
        sample_id = self.generate_sample_id()

        # 生成条形码
        barcode = self.barcode_generator.generate(
            sample_id,
            barcode_type="CODE128"
        )

        # 记录样本信息
        sample = Sample(
            id=sample_id,
            barcode=barcode,
            patient_id=sample_info.patient_id,
            sample_type=sample_info.sample_type,
            collection_datetime=sample_info.collection_datetime,
            collector_id=sample_info.collector_id,
            status="COLLECTED"
        )

        self.tracking_database.insert(sample)

        return sample

    def track_sample_journey(self, sample_id):
        """追踪样本流程"""
        events = self.tracking_database.get_events(sample_id)

        journey = []
        for event in events:
            journey.append({
                "timestamp": event.timestamp,
                "location": event.location,
                "action": event.action,
                "user": event.user,
                "status": event.status
            })

        return SampleJourney(sample_id, journey)

    def update_sample_status(self, sample_id, new_status, location):
        """更新样本状态"""
        event = TrackingEvent(
            sample_id=sample_id,
            timestamp=datetime.now(),
            location=location,
            action=f"状态更新为{new_status}",
            user=self.get_current_user(),
            status=new_status
        )

        self.tracking_database.add_event(event)

中间件集成

双向接口引擎

class InterfaceEngine:
    """接口引擎"""

    def __init__(self):
        self.hl7_interface = HL7Interface()
        self.astm_interface = ASTMInterface()
        self.fhir_interface = FHIRInterface()
        self.message_queue = MessageQueue()

    def route_message(self, message, protocol):
        """路由消息"""
        if protocol == "HL7":
            return self.hl7_interface.process(message)
        elif protocol == "ASTM":
            return self.astm_interface.process(message)
        elif protocol == "FHIR":
            return self.fhir_interface.process(message)
        else:
            raise UnsupportedProtocolError(f"不支持的协议: {protocol}")

    def transform_message(self, message, source_format, target_format):
        """转换消息格式"""
        # 解析源格式
        parsed_data = self.parse_message(message, source_format)

        # 转换为目标格式
        transformed_message = self.format_message(parsed_data, target_format)

        return transformed_message

    def handle_bidirectional_communication(self, instrument_id):
        """处理双向通信"""
        # 监听来自仪器的消息
        incoming_message = self.listen_for_message(instrument_id)

        if incoming_message:
            # 处理结果消息
            result = self.process_result_message(incoming_message)

            # 发送确认
            ack = self.send_acknowledgment(instrument_id)

        # 检查是否有待发送的医嘱
        pending_orders = self.get_pending_orders(instrument_id)

        if pending_orders:
            # 发送医嘱到仪器
            for order in pending_orders:
                self.send_order_to_instrument(instrument_id, order)

相关资源

参考标准

  • HL7 v2.5.1: 健康信息交换标准
  • ASTM E1394: 临床仪器与计算机系统之间的数据传输标准
  • FHIR R4: 快速健康互操作性资源
  • IHE LTW: 实验室测试工作流程

💬 讨论区

欢迎在这里分享您的想法、提出问题或参与讨论。需要 GitHub 账号登录。