글 목록

6개의 글

EMR 프로젝트 - 6

추가한 기능 날짜별 진료 완료 환자 조회 수납 금액 직접 입력 현금, 카드 결제수단 기록 미수납, 수납완료 표시 추가된 테이블 payments id - 기본키 encounter_id - 진료 ID amount - 금액 method - 결제수단 received_by_id - 수납 처리 직원 paid_at - 수납 처리 시각 결과물 수납 전 Sping의 역할 분리를 통해 admin과 간호사 일 때만 수납 관리가 활성화 되게 만들었다. 수납 후

EMR 프로젝트 - 5

이번에 추가한 기능 약품 검색 및 처방: 약품 코드 데이터를 불러오고, 약품 검색 후 투여량, 횟수, 일수, 용법을 입력해 처방 저장 검사, 처치 요청: 진료 중 검사나 처치 항목과 요청 사항 등록 수행 상태 및 결과 관리: 요청 -> 수행 중 -> 완료 상태 관리, 결과 입력과 요청 의사의 확인 환자 과거 기록 조회: 이전 진료의 SOAP, 진단, 처방과 검사, 처치 기록 확인 추가된 테이블 medications : 약품 기준 정보 encounter_prescriptions : 진료별 처방 내역(투여량, 단위, 횟수 등) order_items : 검사, 처치 항목 정보 clinical_orders : 검사, 처치 요청 및 결과 결과물

EMR 프로젝트 - 4

이번에 추가한 기능 기존에는 진료기록을 하나의 note 필드에 자유롭게 작성했다. 이번에는 기록을 목적에 따라 구분할 수 있도록 SOAP 형식으로 변경했다. 접수할 때 입력한 방문 사유인 reason은 별도로 유지하고, 필요하면 S 항목으로 가져올 수 있도록 했다. 상병코드를 검색해 해당 진료의 진단으로 등록할 수 있도록 했다. 병원의 당일 운영 현황을 한눈에 확인할 수 있도록 대시보드를 구현했다. 대기 환자는 접수 순서대로 최대 6명까지 보여주고, 대기 시간이 30분 이상이면 강조했다. 오늘 미접수 예약도 시간순으로 최대 6건까지 표시하며, 예약 시간이 지난 경우 ‘시간 경과’로 구분했다. 추가된 테이블 diagnosis_codes : 진단 선택에 사용하는 상병코드 기준 목록 diagnosis_terms : 하나의 코드에 연결된 여러 명칭 보관 encounter_diagnoses : 특정 진료에서 선택한 진단 보관 결과물 진단코드, 의약품코드 주소 건강보험심사평가원_약가마스터_의약품표준코드_20260831 | 공공데이터포털 (건강보험심사평가원) 한국표준질병사인분류(KCD) 9차 개정에 따른 상병마스터 및 질병코드 모니터링 지표목록 반영 결과 안내 > 공지사항 | 대한보건의료정보관리사협회

EMR 프로젝트 - 3

ERD EMR 프로젝트의 기본 흐름인 환자 등록 -> 예약 또는 당일 접수 -> 진료 대기 -> 진료 완료를 구현했다. 데이터 처리 동시 요청으로 중복 접수가 발생하지 않도록 트랜잭션과 잠금 처리를 적용했다. 예약과 진료기록 수정에는 버전 검사를 사용해 다른 사용자의 변경 내용을 덮어쓰지 않도록 했다. @Lock(LockModeType.PESSIMISTIC_WRITE) @Query("select p from Patient p where p.id = :id") Optional<Patient> findLockedById(@Param("id") Long id); @Transactional public EncounterView register(Registration input) { Patient patient = lockedPatient(input.patientId()); if (encounters.existsByPatientIdAndStatusIn( patient.getId(), List.of(Encounter.Status.WAITING, Encounter.Status.IN_PROGRESS))) { throw new IllegalStateException("이미 대기 또는 진료 중인 접수가 있습니다."); } 구현 환자 관리 환자 목록과 상세정보를 좌우로 나누고, 목록에서 환자를 선택하면 정보를 조회하거나 수정할 수 있도록 구성했다. 기본 인적사항에 더해 알레르기, 과거력, 기저질환, 특이사항을 저장하도록 했다. 편의성을 위해 환자 선택 시 예약 등록, 당일 접수 기능을 같이 사용할 수 있도록 구성했다. 예약관리 예약 관리에서는 날짜별 예약 조회와 날짜, 시간, 담당 의사, 사유 변경, 예약 취소를 지원한다. 예약은 30분 단위이며, 같은 시간에 동일 환자나 담당 의사의 예약이 중복되지 않도록 검사한다. 이미 접수했거나 취소한 예약은 수정할 수 없도록 처리했다. 예약은 방문 예정 정보이고, 접수는 환자가 실제로 방문한 기록이므로 appointments와 encounters 테이블을 분리했다. 등록 후 별도로 접수해야 진료 대기 목록에 들어간다. 진료 관리 진료 관리에서는 접수 시각이 빠른 순서로 환자를 보여주고, 접수 시각과 대기 시간을 표시한다. 기본 목록에는 대기, 진료 중인 환자만 표시하며, 완료된 기록은 별도 필터로 조회한다. 추가할 내용 진단명 등록, 약 처방, 의사가 환자에게 검사 요청과 결과, 처치 및 수납까지 추가하고 마무리할 예정이다.

EMR 프로젝트 - 2

WPF 클라이언트와 Spring Boot 서버 연결 로그인에 사용할 회원 정보를 JPA 엔티티로 정의했다. 이메일은 로그인 식별자로 사용하기 때문에 중복되지 않도록 설정했고, 역할은 문자열로 저장하도록 구성했고, 역할은 DOCTOR, NURSE, ADMIN으로 구분했다. 만들고 있는 티켓 사이트와 비슷한 스프링 시큐리티 구조를 가지고 있다. WPF에서 로그인 요청과 세션 쿠키 관리 WPF의 서버 통신은 AuthService에서 처리하도록 구성했다. 로그인 상태를 유지하기 위해 HttpClientHandler에 CookieContainer를 연결했다. private AuthService() { _cookieContainer = new CookieContainer(); var handler = new HttpClientHandler { CookieContainer = _cookieContainer, UseCookies = true }; _httpClient = new HttpClient(handler) { BaseAddress = new Uri("http://localhost:8080") }; } 로그인 요청에서는 Spring Security의 폼 로그인 형식에 맞춰 FormUrlEncodedContent를 사용했다. var formData = new Dictionary<string, string> { { "email", email.Trim() }, { "password", password } }; var content = new FormUrlEncodedContent(formData); var response = await _httpClient.PostAsync( "/api/auth/login", content); 로그인에 성공하면 같은 클라이언트로 내 정보 API를 호출한다. var meResponse = await _httpClient.GetAsync("/api/auth/me"); if (meResponse.IsSuccessStatusCode) { var json = await meResponse.Content.ReadAsStringAsync(); CurrentUser = JsonSerializer.Deserialize<MemberResponse>(json); } 로그인 시 프로그램이 종료되던 문제 ShutdownMode = ShutdownMode.OnExplicitShutdown; var loginWindow = new LoginWindow(); bool? result = loginWindow.ShowDialog(); if (result == true) { var mainWindow = new MainWindow(); MainWindow = mainWindow; ShutdownMode = ShutdownMode.OnMainWindowClose; mainWindow.Show(); } else { Shutdown(); } } 로그인 창이 닫히고 메인 창이 열리기 전까지 앱이 유지되어야 한다. 따라서 로그인 중에는 OnExplicitShutdown을 사용하고, 메인 창을 지정한 뒤에는 OnMainWindowClose로 변경했다. 결과물

EMR 프로젝트 - 1

병원 관리 프로그램을 만들면서 WPF로 기본 화면을 구성하고, MVVM 패턴을 적용해 메뉴에 따라 화면이 전환되도록 구현했다. 이번에는 대시보드와 환자 관리 화면을 연결하면서 XAML, 데이터 바인딩, Command가 어떻게 함께 동작하는지 배웠다. XAML로 기본 화면 구성하기 화면은 왼쪽 사이드바, 상단 제목, 본문 영역으로 나눴다. - Grid: 행과 열로 전체 레이아웃 구성 - StackPanel: 메뉴와 텍스트를 순서대로 배치 - Border: 배경색, 테두리, 여백 설정 - UserControl: 대시보드와 환자 관리 화면을 별도 구성 MVVM으로 화면과 동작 분리하기 MVVM은 Model, View, ViewModel로 역할을 나누는 구조다. View와 ViewModel을 분리하는 데 집중했다. 대시보드와 환자 관리 화면을 각각 UserControl로 만들고, MainViewModel에서 어떤 화면을 보여줄지 관리하도록 구성했다. Model과 Service는 폴더만 준비한 상태이며, 실제 데이터 처리는 이후에 구현할 예정이다. DataContext와 Binding으로 화면 연결하기 View에서 ViewModel의 속성을 사용하려면 먼저 DataContext를 설정해야 한다. public MainWindow() { InitializeComponent(); DataContext = new ViewModels.MainViewModel(); } 이렇게 설정하면 XAML의 Binding이 해당 ViewModel의 속성을 참조한다. <TextBlock Text="{Binding CurrentPageTitle}" /> 화면 제목을 XAML에 고정해서 작성하는 대신, ViewModel의 CurrentPageTitle 값으로 표시하도록 연결했다. 속성 변경을 화면에 알리기 바인딩된 값이 실행 중에 바뀌었을 때 화면도 갱신하려면 속성 변경 알림이 필요하다. 이를 위해 CommunityToolkit.Mvvm의 ObservableObject와 [ObservableProperty]를 사용했다. public partial class MainViewModel : ObservableObject { [ObservableProperty] [NotifyPropertyChangedFor(nameof(CurrentPageTitle))] private ObservableObject currentViewModel; public string CurrentPageTitle => CurrentViewModel is PatientViewModel ? "환자 관리" : "대시보드"; } DataTemplate으로 ViewModel에 맞는 화면 표시하기 본문에는 ContentControl을 배치했다. <ContentControl Content="{Binding CurrentViewModel}" /> 그리고 App.xaml에 ViewModel 타입별로 표시할 View를 등록했다. <DataTemplate DataType="{x:Type vm:DashboardViewModel}"> <views:DashboardView /> </DataTemplate> <DataTemplate DataType="{x:Type vm:PatientViewModel}"> <views:PatientView /> </DataTemplate> ContentControl에 전달된 객체가 PatientViewModel이면 WPF가 대응하는 템플릿을 찾아 PatientView를 표시한다. 결과물