using System.Collections.ObjectModel; using System.Windows; using SheetMe.Data.Stores; using SheetMe.Designer.Services; namespace SheetMe.Designer.Views; /// /// 서식별 상용구 관리 대화상자 — E_SHTWRDMST 1단계 문구 추가/수정/삭제/순서. /// 레거시 런타임 상용구 팝업(MRecordWord)이 그대로 읽어가는 데이터를 관리한다. /// public partial class RecordWordDialogView : Window { #region Member Fields private readonly RecordWordStore store; private readonly string shtCod; private readonly string auditUid; private readonly bool canWrite; private readonly ObservableCollection words = new(); #endregion #region Constructors /// 감사 컬럼(ShtUpdUid/ShtFstUid)에 기록할 HIS 사용자 코드 /// DB 쓰기 가능 여부 — 미인증/게이트 차단이면 읽기 전용으로 연다 public RecordWordDialogView(RecordWordStore store, string shtCod, string sheetTitle, string auditUid, bool canWrite) { this.store = store; this.shtCod = shtCod; this.auditUid = auditUid; this.canWrite = canWrite; InitializeComponent(); HeaderText.Text = $"[{shtCod}] {sheetTitle} — 작성 화면의 상용구 팝업에 표시되는 문구입니다. " + "(텍스트박스의 '상용구 사용'이 켜져 있어야 합니다)" + (canWrite ? string.Empty : "\n※ HIS 사용자가 확인되지 않아 읽기 전용입니다."); WordList.ItemsSource = words; Loaded += (_, _) => Reload(); NewWordBox.Loaded += (_, _) => NewWordBox.Focus(); } #endregion #region Methods - 가드 /// 쓰기 전 확인 — 미인증이면 안내 후 차단(감사 컬럼에 남길 주체가 없다) private bool EnsureWritable() { if (canWrite) { return true; } DialogService.Notify(DialogKind.Warning, "상용구 관리", "HIS 사용자가 확인되지 않아 상용구를 변경할 수 없습니다.", "기록지정보 화면에서 서식생성기를 실행해 주세요.", this); return false; } #endregion #region Methods private void Reload() { try { words.Clear(); foreach (var word in store.List(shtCod)) { words.Add(word); } } catch (Exception ex) { DialogService.Notify(DialogKind.Error, "오류", "상용구 조회 중 오류가 발생했습니다.", ex.Message, this); } } private void OnAdd(object sender, RoutedEventArgs e) { var value = NewWordBox.Text.Trim(); if (value.Length == 0 || !EnsureWritable()) { return; } try { store.Add(shtCod, value, auditUid); NewWordBox.Clear(); NewWordBox.Focus(); Reload(); WordList.SelectedIndex = words.Count - 1; } catch (Exception ex) { DialogService.Notify(DialogKind.Error, "오류", "추가 중 오류가 발생했습니다.", ex.Message, this); } } private void OnEdit(object sender, RoutedEventArgs e) { if (WordList.SelectedItem is not RecordWordInfo selected || !EnsureWritable()) { return; } // QueryEditorWindow 재사용(큰 다중행 편집 영역) — SQL 이 아니므로 치환 변수 패널은 숨긴다 var editor = new QueryEditorWindow("상용구 수정", selected.Value, showVariables: false) { Owner = this }; if (editor.ShowDialog() != true) { return; } var newValue = editor.QueryText.Trim(); if (newValue.Length == 0 || newValue == selected.Value) { return; } try { store.Update(selected.Key, newValue, auditUid); Reload(); } catch (Exception ex) { DialogService.Notify(DialogKind.Error, "오류", "수정 중 오류가 발생했습니다.", ex.Message, this); } } private void OnRemove(object sender, RoutedEventArgs e) { if (WordList.SelectedItem is not RecordWordInfo selected || !EnsureWritable()) { return; } if (!DialogService.Confirm("상용구 삭제", "삭제할까요?", Truncate(selected.Value), yes: "삭제", no: "취소", destructive: true, owner: this)) { return; } try { store.Remove(selected.Key, auditUid); Reload(); } catch (Exception ex) { DialogService.Notify(DialogKind.Error, "오류", "삭제 중 오류가 발생했습니다.", ex.Message, this); } } private void OnMoveUp(object sender, RoutedEventArgs e) => Move(-1); private void OnMoveDown(object sender, RoutedEventArgs e) => Move(+1); private void Move(int delta) { var index = WordList.SelectedIndex; var target = index + delta; if (index < 0 || target < 0 || target >= words.Count || !EnsureWritable()) { return; } try { words.Move(index, target); store.Reorder(words.Select(w => w.Key).ToList(), auditUid); WordList.SelectedIndex = target; } catch (Exception ex) { DialogService.Notify(DialogKind.Error, "오류", "순서 변경 중 오류가 발생했습니다.", ex.Message, this); Reload(); } } private static string Truncate(string value) => value.Length > 80 ? value[..80] + "…" : value; #endregion }