Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6b456753c | ||
|
|
d83478619e | ||
|
|
e162d0fb6b |
@@ -1112,6 +1112,40 @@ public static class EditSmoke
|
||||
$"ValueText='{choiceRow.ValueText}' IsMixed={choiceRow.IsMixed}");
|
||||
}
|
||||
|
||||
// 15-a00000) 태그 행이 사실대로 말하는가.
|
||||
{
|
||||
// 카탈로그에 없는 이름은 표식이 붙어야 한다 — 그러나 <b>막지는 않는다</b>.
|
||||
// 인라인으로 직접 치는 것이 주 경로인데 검증이 하나도 없어서,
|
||||
// 한 글자 틀려도 조용히 커밋되고 미리보기에서 빈칸으로만 드러났다.
|
||||
var tagRow2 = new ViewModels.Inspector.TagPickerRowViewModel("데이터 태그",
|
||||
"데이터 태그 선택", SheetMe.Core.Catalog.LegacyTagCatalog.DataInterfaceTags,
|
||||
new[] { "PAT_이름" });
|
||||
|
||||
tagRow2.Initialize("PAT_이름");
|
||||
Check("태그: 카탈로그에 있는 이름은 표식이 없다", !tagRow2.IsUnknownTag);
|
||||
|
||||
tagRow2.ValueText = "PAT_이룸"; // 한 글자 오타
|
||||
Check("태그: 카탈로그에 없는 이름에 표식이 붙는다", tagRow2.IsUnknownTag);
|
||||
Check("태그: 그래도 값은 그대로 둔다(사이트 커스텀 태그)", tagRow2.ValueText == "PAT_이룸",
|
||||
tagRow2.ValueText);
|
||||
|
||||
tagRow2.Initialize(string.Empty);
|
||||
Check("태그: 빈 값은 표식 대상이 아니다", !tagRow2.IsUnknownTag);
|
||||
tagRow2.Initialize(null, isMixed: true);
|
||||
Check("태그: 값이 갈리면 표식을 내지 않는다", !tagRow2.IsUnknownTag);
|
||||
|
||||
// 로그인 사용자 태그 — 피커가 쓰던 5-인자판은 면허·전문의·직종·부서·부서전화를
|
||||
// 빈 문자열로 채워, 종이에는 값이 찍히는데 피커에서만 "비어 있습니다"가 나왔다
|
||||
var withFields = SheetMe.Core.Catalog.TagPreviewCatalog.FromUser(
|
||||
"ETC_로그인_의사면허번호", "011825", "홍길동", "010", "02",
|
||||
"면허12345", "전문의678", "의사", "내과", "1234");
|
||||
var withoutFields = SheetMe.Core.Catalog.TagPreviewCatalog.FromUser(
|
||||
"ETC_로그인_의사면허번호", "011825", "홍길동", "010", "02");
|
||||
Check("태그: 면허번호는 10-인자판에서만 값이 나온다",
|
||||
withFields == "면허12345" && withoutFields.Length == 0,
|
||||
$"10인자='{withFields}' 5인자='{withoutFields}'");
|
||||
}
|
||||
|
||||
// 15-a0000) 레이어 목록이 계층과 범위를 말하는가.
|
||||
//
|
||||
// 사용자가 콕 집어 "레이어 구분이 잘 안 된다"고 한 곳이다. 원인은 색이 아니라 <b>산수</b>였다 —
|
||||
|
||||
@@ -918,9 +918,10 @@ public sealed class InspectorViewModel : ViewModelBase
|
||||
PropEditorKind.DataInterfaceTag => new TagPickerRowViewModel(def.Label,
|
||||
"데이터 태그 선택 — 자동 채움 원천(bzDataInterface)", LegacyTagCatalog.DataInterfaceTags,
|
||||
LegacyTagUsageCatalog.SuggestFor(def.Key, controlType)),
|
||||
// 액션은 값이 아니라 동작이다 — 피커가 데이터 태그용 값·사유 칸을 그리면 안 된다
|
||||
PropEditorKind.DataActionTag => new TagPickerRowViewModel(def.Label,
|
||||
"액션 태그 선택 — 더블클릭/버튼 액션(EN_DataActionTyp)", LegacyTagCatalog.DataActionTags,
|
||||
LegacyTagUsageCatalog.SuggestFor(def.Key, controlType)),
|
||||
LegacyTagUsageCatalog.SuggestFor(def.Key, controlType)) { IsActionTag = true },
|
||||
PropEditorKind.SqlQuery => new QueryRowViewModel(def.Label),
|
||||
PropEditorKind.Mask => new MaskRowViewModel(def.Label),
|
||||
// 배선 대상 목록은 '지금 이 서식'의 데이터소스다 — 런타임도 같은 서식 안에서만 이름을 찾는다
|
||||
|
||||
@@ -503,6 +503,29 @@ public sealed class TagPickerRowViewModel : PropertyRowViewModel
|
||||
/// <summary>피커 대화상자 제목</summary>
|
||||
public string PickerTitle { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 액션 태그 행인가 — 액션은 <b>값이 아니라 동작</b>이라 피커의 값·사유 칸 뜻이 다르다.
|
||||
/// 데이터 태그용 문구를 그대로 쓰면 149종 전부에서 그 칸이 거짓이 된다.
|
||||
/// </summary>
|
||||
public bool IsActionTag { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 카탈로그에 없는 이름인가 — <b>값은 건드리지 않고</b> 표식만 낸다.
|
||||
///
|
||||
/// 인라인 완성으로 직접 치는 것이 이 행의 주 경로인데 거기에는 검증이 하나도 없었다.
|
||||
/// 'PAT_이룸' 처럼 한 글자 틀리면 아무 표시 없이 커밋되고, 그 사실은 미리보기에서
|
||||
/// <b>빈칸</b>으로만 드러난다 — 빈칸의 원인이 오타인지 이 환자에게 자료가 없어서인지 가릴 수 없다.
|
||||
///
|
||||
/// 막지는 않는다. 사이트마다 카탈로그에 없는 커스텀 태그를 쓰기 때문이다(글꼴 행과 같은 규칙).
|
||||
/// </summary>
|
||||
public bool IsUnknownTag => !IsMixed && ValueText.Length > 0
|
||||
&& !string.Equals(ValueText, "None", StringComparison.Ordinal)
|
||||
&& !Choices.Contains(ValueText, StringComparer.Ordinal);
|
||||
|
||||
/// <summary>경고 문구 — 툴팁으로 보인다</summary>
|
||||
public string UnknownTagHint => $"'{ValueText}' 은(는) 카탈로그에 없는 이름입니다. "
|
||||
+ "사이트 전용 태그면 그대로 두고, 오타면 고치세요 — 값이 안 나오면 종이에서 빈칸이 됩니다.";
|
||||
|
||||
/// <summary>
|
||||
/// 한 줄에 하나꼴로 접히는 긴 한글 태그를 몇 개까지 깔지.
|
||||
/// 인스펙터 폭이 좁아 칩이 세로로 쌓인다 — 8개를 넘기면 다른 속성이 화면 밖으로 밀린다.
|
||||
@@ -676,13 +699,16 @@ public sealed class TagPickerRowViewModel : PropertyRowViewModel
|
||||
if (e.PropertyName == nameof(ValueText))
|
||||
{
|
||||
OnPropertyChanged(nameof(ShowSuggestions));
|
||||
// 값이 바뀌면 '카탈로그에 없음' 표식도 다시 판정한다
|
||||
OnPropertyChanged(nameof(IsUnknownTag));
|
||||
OnPropertyChanged(nameof(UnknownTagHint));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void OnBrowse()
|
||||
{
|
||||
var dialog = new Views.TagPickerDialogView(PickerTitle, Choices, ValueText, preferredAll)
|
||||
var dialog = new Views.TagPickerDialogView(PickerTitle, Choices, ValueText, preferredAll, IsActionTag)
|
||||
{
|
||||
Owner = System.Windows.Application.Current.MainWindow,
|
||||
};
|
||||
|
||||
@@ -622,6 +622,16 @@
|
||||
<Button DockPanel.Dock="Right" Width="28" Height="26" Padding="0" Margin="4,0,0,0"
|
||||
Command="{Binding BrowseCommand}" ToolTip="전체 목록에서 선택"
|
||||
Content="{Binding Source=list, Converter={StaticResource IconName}, ConverterParameter=13}"/>
|
||||
<!--
|
||||
카탈로그에 없는 이름 — 글꼴 행과 같은 규칙이다. 값은 건드리지 않고 표식만 낸다.
|
||||
인라인으로 직접 치는 것이 이 행의 주 경로인데 검증이 하나도 없어서,
|
||||
한 글자 틀려도 조용히 커밋되고 미리보기에서 <b>빈칸</b>으로만 드러났다 —
|
||||
빈칸의 원인이 오타인지 자료가 없어서인지 가릴 수 없었다.
|
||||
-->
|
||||
<TextBlock DockPanel.Dock="Right" Text="⚠" FontSize="13" VerticalAlignment="Center"
|
||||
Margin="4,0,0,0" Foreground="{DynamicResource B.Warning}"
|
||||
ToolTip="{Binding UnknownTagHint}"
|
||||
Visibility="{Binding IsUnknownTag, Converter={StaticResource BoolToVisibility}}"/>
|
||||
<Grid>
|
||||
<TextBox x:Name="TagInput" Style="{StaticResource RowInput}"
|
||||
bh:InspectorFieldBehavior.CommitOnEnter="True"
|
||||
|
||||
@@ -52,10 +52,10 @@
|
||||
<TextBlock Text="기준 시점" VerticalAlignment="Center" Margin="0,0,6,0"
|
||||
Foreground="{DynamicResource B.Muted}"
|
||||
ToolTip="입원 내원은 구간이라 어느 시점의 진료과·병실·보험 자격을 쓸지 정해야 합니다. 외래는 접수일시로 같습니다."/>
|
||||
<ComboBox x:Name="EdgeCombo" Width="92" SelectedIndex="0"
|
||||
<ComboBox x:Name="EdgeCombo" Width="150" SelectedIndex="0"
|
||||
AutomationProperties.Name="기준 시점">
|
||||
<ComboBoxItem Content="마지막"/>
|
||||
<ComboBoxItem Content="처음"/>
|
||||
<ComboBoxItem Content="마지막(퇴원 시점)"/>
|
||||
<ComboBoxItem Content="처음(입원 시점)"/>
|
||||
</ComboBox>
|
||||
<Button x:Name="SelectButton" Content="선택" Padding="20,4" Margin="10,0,0,0"
|
||||
Click="OnSelect" IsDefault="True" IsEnabled="False"
|
||||
@@ -132,12 +132,16 @@
|
||||
AutomationProperties.Name="내원 목록">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Header="구분" Width="52" DisplayMemberBinding="{Binding Kind}"/>
|
||||
<GridViewColumn Header="접수일시" Width="118" DisplayMemberBinding="{Binding AcceptedAtText}"/>
|
||||
<GridViewColumn Header="진료과" Width="100" DisplayMemberBinding="{Binding Department}"/>
|
||||
<GridViewColumn Header="담당의" Width="80" DisplayMemberBinding="{Binding Doctor}"/>
|
||||
<GridViewColumn Header="보험" Width="86" DisplayMemberBinding="{Binding Insurance}"/>
|
||||
<GridViewColumn Header="상태" Width="66" DisplayMemberBinding="{Binding State}"/>
|
||||
<GridViewColumn Header="구분" Width="46" DisplayMemberBinding="{Binding Kind}"/>
|
||||
<GridViewColumn Header="접수일시" Width="106" DisplayMemberBinding="{Binding AcceptedAtText}"/>
|
||||
<!-- 퇴원일시 — 이미 조회돼 있는데 화면에 없었다.
|
||||
입원 내원이 '구간'이라는 사실이 이 열 하나로 눈에 보인다.
|
||||
그래야 아래 기준 시점 선택이 무슨 뜻인지 알 수 있다. -->
|
||||
<GridViewColumn Header="퇴원일시" Width="106" DisplayMemberBinding="{Binding LeftAtText}"/>
|
||||
<GridViewColumn Header="진료과" Width="86" DisplayMemberBinding="{Binding Department}"/>
|
||||
<GridViewColumn Header="담당의" Width="68" DisplayMemberBinding="{Binding Doctor}"/>
|
||||
<GridViewColumn Header="보험" Width="74" DisplayMemberBinding="{Binding Insurance}"/>
|
||||
<GridViewColumn Header="상태" Width="58" DisplayMemberBinding="{Binding State}"/>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
|
||||
@@ -86,6 +86,15 @@ public partial class PatientPickerDialogView : Window
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>검색 유형의 사람이 읽는 이름 — 0건 안내가 "무엇으로 찾았는지" 말할 때 쓴다</summary>
|
||||
private static string KindLabel(PatientSearchKind kind) => kind switch
|
||||
{
|
||||
PatientSearchKind.Name => "성명 접두일치",
|
||||
PatientSearchKind.ResidentNumber => "주민번호 접두일치",
|
||||
PatientSearchKind.MobilePhone => "휴대전화 부분일치",
|
||||
_ => "차트번호 완전일치",
|
||||
};
|
||||
|
||||
private void OnSearch(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (store is null)
|
||||
@@ -111,10 +120,42 @@ public partial class PatientPickerDialogView : Window
|
||||
Mouse.OverrideCursor = Cursors.Wait;
|
||||
SearchButton.IsEnabled = false;
|
||||
var found = store.Search(kind, TermBox.Text);
|
||||
var padded = string.Empty;
|
||||
|
||||
// 차트번호는 <b>완전일치</b>다. 병원마다 자릿수가 정해져 있어 실제 값은 0으로 채워져 있는데
|
||||
// (P_PatInf 가 고정 폭이다) 사람은 "12345" 처럼 앞의 0 을 빼고 친다 — 그러면 0건이다.
|
||||
// 저장소는 주석으로 "병원별 zero-pad 후 전달"을 요구하는데 이 호출부가 그걸 안 지켰다.
|
||||
//
|
||||
// <b>자릿수를 설정으로 정하지 않는다.</b> 병원마다 다르고 틀리면 멀쩡한 검색을 망친다.
|
||||
// 대신 0건일 때만 한 번 더 찾는다 — 8·10자리는 레거시가 쓰던 두 폭이다.
|
||||
// 찾았으면 무엇으로 찾았는지 칸에 되써서 사용자가 그 번호를 기억하게 한다.
|
||||
if (found.Count == 0 && kind == PatientSearchKind.ChartNumber
|
||||
&& TermBox.Text.Trim() is { Length: > 0 } typed && typed.All(char.IsDigit))
|
||||
{
|
||||
foreach (var width in new[] { 8, 10 })
|
||||
{
|
||||
if (typed.Length >= width)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var retry = store.Search(kind, typed.PadLeft(width, '0'));
|
||||
if (retry.Count > 0)
|
||||
{
|
||||
found = retry;
|
||||
padded = typed.PadLeft(width, '0');
|
||||
TermBox.Text = padded;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PatientList.ItemsSource = found;
|
||||
PatientCountText.Text = found.Count switch
|
||||
{
|
||||
0 => "환자 — 없습니다",
|
||||
// 0건일 때 <b>무엇으로 찾았는지</b> 말한다 — 유형이 틀려서 0건인 경우가 가장 흔한데
|
||||
// 전에는 그 힌트가 화면에 하나도 없어 접속이나 권한을 의심하게 됐다
|
||||
0 => $"환자 — 없습니다({KindLabel(kind)}로 찾았습니다)",
|
||||
_ when padded.Length > 0 => $"환자 {found.Count}명 — 자릿수를 채워 '{padded}' 로 찾았습니다",
|
||||
PatientVisitStore.DefaultLimit =>
|
||||
$"환자 {found.Count}명 — 상한에 걸렸습니다. 검색어를 좁히세요",
|
||||
_ => $"환자 {found.Count}명",
|
||||
|
||||
@@ -422,8 +422,11 @@
|
||||
|
||||
<!-- 검색: 돋보기를 겹쳐 둔다 — 빈 상자만 있으면 무엇을 하는 칸인지 안 읽힌다 -->
|
||||
<Grid DockPanel.Dock="Top" Margin="0,0,0,8">
|
||||
<!-- KeyDown 필수 — 확인 버튼이 IsDefault 라 이 칸의 Enter 가
|
||||
'저장하고 닫기'로 새어 나간다(변수를 못 넣은 채 편집이 끝난다) -->
|
||||
<TextBox x:Name="VariableSearch" Padding="28,4,8,4"
|
||||
VerticalContentAlignment="Center" TextChanged="OnVariableSearchChanged"
|
||||
KeyDown="OnVariableSearchKeyDown"
|
||||
AutomationProperties.Name="치환 변수 검색"
|
||||
ToolTip="변수명·설명·초성으로 찾습니다 (예: ㅊㅌㅂㅎ → 차트번호)"/>
|
||||
<TextBlock Text="🔍" FontSize="11" Margin="9,0,0,0" IsHitTestVisible="False"
|
||||
|
||||
@@ -41,6 +41,9 @@ public partial class QueryEditorWindow : Window
|
||||
/// <summary>마지막으로 돌린 SQL — 진단이 "무엇을 돌렸는가"를 확인할 때 쓴다</summary>
|
||||
private string lastTrialSql = string.Empty;
|
||||
|
||||
/// <summary>검증을 돌린 시점의 SQL 원문 — 그 뒤 고쳤는지 판정한다</summary>
|
||||
private string trialBaseline = string.Empty;
|
||||
|
||||
/// <summary>진단 전용 — 검증 실행이 실제로 만든 SQL</summary>
|
||||
internal string LastTrialSql => lastTrialSql;
|
||||
|
||||
@@ -552,6 +555,8 @@ public partial class QueryEditorWindow : Window
|
||||
emptyPlaceholder: "NULL");
|
||||
var probe = converted.Sql;
|
||||
lastTrialSql = probe;
|
||||
// 치환 <b>전</b> 원문을 기준으로 삼는다 — 사용자가 고치는 것은 이쪽이다
|
||||
trialBaseline = SqlBox.Text;
|
||||
|
||||
Mouse.OverrideCursor = Cursors.Wait;
|
||||
SheetMe.Data.Stores.QueryTrialResult result;
|
||||
@@ -736,8 +741,38 @@ public partial class QueryEditorWindow : Window
|
||||
LengthText.Text = $"{text.Length:N0}자 · {CountLines(text)}줄";
|
||||
UpdateCaretText();
|
||||
UpdateProblems(text);
|
||||
RefreshTrialFreshness();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 검증 결과가 <b>지금 SQL 의 것인지</b> 표시한다.
|
||||
///
|
||||
/// 전에는 검증을 돌린 뒤 SQL 을 고쳐도 초록 요약과 결과 표가 그대로 남았다.
|
||||
/// "검증했다"고 믿고 저장하는데, 저장되는 것은 <b>검증하지 않은 문장</b>이다.
|
||||
/// 결과를 지우지는 않는다 — 방금 본 컬럼명이 사라지면 그것대로 불편하다.
|
||||
/// 흐리게 낮추고 다시 돌리라고 말하는 것으로 충분하다.
|
||||
/// </summary>
|
||||
private void RefreshTrialFreshness()
|
||||
{
|
||||
if (TrialPane is null || TrialPane.Visibility != Visibility.Visible || trialBaseline.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var stale = !string.Equals(trialBaseline, SqlBox.Text, StringComparison.Ordinal);
|
||||
TrialPane.Opacity = stale ? 0.5 : 1.0;
|
||||
if (stale && !TrialSummary.Text.StartsWith(StaleMark, StringComparison.Ordinal))
|
||||
{
|
||||
TrialSummary.Text = StaleMark + TrialSummary.Text;
|
||||
}
|
||||
else if (!stale && TrialSummary.Text.StartsWith(StaleMark, StringComparison.Ordinal))
|
||||
{
|
||||
TrialSummary.Text = TrialSummary.Text[StaleMark.Length..];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>검증 이후 SQL 이 바뀌었을 때 요약 앞에 붙는 표시</summary>
|
||||
private const string StaleMark = "(수정됨 — 다시 실행하세요) ";
|
||||
|
||||
/// <summary>줄·열 표시 — 오류 메시지의 위치를 찾아갈 때 쓴다</summary>
|
||||
private void UpdateCaretText()
|
||||
{
|
||||
@@ -1047,6 +1082,35 @@ public partial class QueryEditorWindow : Window
|
||||
#endregion
|
||||
|
||||
#region Methods - Variables
|
||||
/// <summary>
|
||||
/// 변수 검색칸의 Enter·↓ — <b>확인 버튼으로 새어 나가는 것을 막는다</b>.
|
||||
///
|
||||
/// 확인 버튼이 <c>IsDefault</c> 라, 이 칸에서 Enter 를 누르면 검색이나 삽입이 아니라
|
||||
/// <b>SQL 이 저장되고 창이 닫혔다</b>. '차트' 를 치고 Enter 를 눌렀을 뿐인데
|
||||
/// 변수를 하나도 못 넣은 채 편집이 끝난다 — 무엇이 일어났는지도 알기 어렵다.
|
||||
///
|
||||
/// Enter 는 지금 걸러진 목록의 선택 항목을 넣는다(필터가 하나로 좁혀졌을 때가 대부분이다).
|
||||
/// ↓ 는 목록으로 이동한다 — 손을 마우스로 옮기지 않고 훑을 수 있어야 한다.
|
||||
/// </summary>
|
||||
private void OnVariableSearchKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
InsertSelectedVariable();
|
||||
e.Handled = true; // IsDefault 버튼에 도달시키지 않는다
|
||||
return;
|
||||
}
|
||||
if (e.Key == Key.Down && VariableList.Items.Count > 0)
|
||||
{
|
||||
VariableList.Focus();
|
||||
if (VariableList.SelectedIndex < 0)
|
||||
{
|
||||
VariableList.SelectedIndex = 0;
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnVariableSearchChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
SearchPlaceholder.Visibility = VariableSearch.Text.Length == 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
@@ -64,6 +64,9 @@ public partial class TagPickerDialogView : Window
|
||||
/// </summary>
|
||||
private readonly IReadOnlyList<string> preferred;
|
||||
|
||||
/// <summary>액션 태그 목록인가 — 값 칸의 뜻이 데이터 태그와 완전히 다르다</summary>
|
||||
private readonly bool isActionKind;
|
||||
|
||||
private const string FilterAll = "*";
|
||||
private const string FilterPreferred = "!";
|
||||
private const string FilterUsed = "+";
|
||||
@@ -81,11 +84,16 @@ public partial class TagPickerDialogView : Window
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
/// <param name="isActionTag">
|
||||
/// 액션 태그 목록인가 — 액션은 <b>값이 아니라 동작</b>이라 값·사유 칸의 뜻이 완전히 다르다.
|
||||
/// 데이터 태그용 문구를 그대로 쓰면 149종 전부에서 오른쪽 설명이 거짓이 된다.
|
||||
/// </param>
|
||||
public TagPickerDialogView(string title, IReadOnlyList<string> tags, string? currentValue,
|
||||
IReadOnlyList<string>? preferredTags = null)
|
||||
IReadOnlyList<string>? preferredTags = null, bool isActionTag = false)
|
||||
{
|
||||
allTags = tags;
|
||||
preferred = preferredTags ?? Array.Empty<string>();
|
||||
isActionKind = isActionTag;
|
||||
previewStore = new SheetMe.Data.Stores.TagPreviewStore(
|
||||
Services.ConfigService.Current.ConnectionString);
|
||||
InitializeComponent();
|
||||
@@ -295,13 +303,21 @@ public partial class TagPickerDialogView : Window
|
||||
/// </summary>
|
||||
private void ShowTagValue(string tag)
|
||||
{
|
||||
if (previewStore is null || !previewStore.CanUseDb)
|
||||
{
|
||||
InfoValueBlock.Visibility = Visibility.Collapsed;
|
||||
return;
|
||||
}
|
||||
InfoValueBlock.Visibility = Visibility.Visible;
|
||||
|
||||
// 액션 태그는 <b>값이 아니다</b>. 더블클릭·버튼이 실행하는 동작이라
|
||||
// "환자 정보가 있어야 값이 나옵니다" 같은 데이터 태그용 사유를 붙이면
|
||||
// 149종 전부에서 이 칸이 통째로 거짓말을 한다.
|
||||
if (isActionKind)
|
||||
{
|
||||
InfoValue.Text = "값이 아니라 동작입니다";
|
||||
InfoValueNote.Text = "더블클릭·버튼에서 실행됩니다 — 종이에 찍히는 값이 아닙니다.";
|
||||
return;
|
||||
}
|
||||
|
||||
// 값을 <b>만들 수 없는 이유</b>는 DB 없이도 안다(정적 판정이다).
|
||||
// 전에는 DB 가드가 이 위에 있어서, 접속이 없으면 사유까지 통째로 감춰졌다 —
|
||||
// 정작 그 사유가 가장 필요한 상황(접속 안 된 단말에서 서식을 훑을 때)에 안 보였다.
|
||||
if (!TagPreviewCatalog.CanResolve(tag))
|
||||
{
|
||||
InfoValue.Text = "값을 만들 수 없습니다";
|
||||
@@ -309,12 +325,29 @@ public partial class TagPickerDialogView : Window
|
||||
return;
|
||||
}
|
||||
|
||||
// 여기서부터는 실제 값이 필요하다 — 그때만 DB 를 따진다.
|
||||
// (진단 스크린샷은 DB 없이 이 창을 띄우므로 이 가드가 없으면 늘 "값을 읽지 못했습니다"가 찍힌다)
|
||||
if (previewStore is null || !previewStore.CanUseDb)
|
||||
{
|
||||
InfoValue.Text = "값은 접속된 단말에서 확인됩니다";
|
||||
InfoValueNote.Text = TagPreviewCatalog.SourceText(tag);
|
||||
return;
|
||||
}
|
||||
|
||||
previewContext ??= previewStore.Read(UserSession.Current.UidCod, UserSession.Current.UidNam);
|
||||
var context = previewContext.Value;
|
||||
var value = TagPreviewCatalog.KindOf(tag) == TagPreviewKind.Clock
|
||||
? TagPreviewCatalog.FromClock(tag, context.Minute12)
|
||||
// <b>본판(10-인자)으로 부른다.</b> 5-인자 위임판은 면허·전문의·직종·부서·부서전화를
|
||||
// 빈 문자열로 채운다 — 그래서 의사면허번호·전문의번호·직종·부서·부서전화 계열이
|
||||
// 피커에서는 "이 계정에는 값이 비어 있습니다"로 보이는데 종이에는 실제 값이 찍혔다.
|
||||
// 값이 나오는 사용자 태그 중 다섯 갈래가 <b>피커에서만</b> 거짓말을 하고 있었다.
|
||||
// 이 값들은 로그인 세션이 이미 들고 있다(HisUser 15컬럼) — 조회를 더 하지 않는다.
|
||||
: TagPreviewCatalog.FromUser(tag, context.UidCod, context.UidNam,
|
||||
context.MobilePhone, context.OfficePhone);
|
||||
context.MobilePhone, context.OfficePhone,
|
||||
UserSession.Current.LicenseNumber, UserSession.Current.SpecialistNumber,
|
||||
UserSession.Current.JobName, UserSession.Current.DepNam,
|
||||
UserSession.Current.DepPhone);
|
||||
|
||||
if (value.Length > 0)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user