Clinical: SubjectType 아래 Subject(optional 자유 식별자) 필드 추가

회의 추가 결정: Phantom/Human/ETC 카테고리 안에서도 표본을 구분하기 위한
자유 텍스트 식별자가 필요. 예: "500mL phantom", "S001", "small phantom v2".

ClinicalSession 모델:
  - val subject: String = "" (optional, 기본값 빈 문자열)
  - folderName: prefix로 포함 (비어있으면 생략)
    예: PHANTOM-500mL_VBT26050202_SUPINE_ALIGN_0CM_2026-06-09_15-30-00
    예 (subject 없음): PHANTOM_VBT26050202_SUPINE_ALIGN_0CM_2026-06-09_15-30-00
  - 폴더명 안전 문자만 (특수문자 → '-'), testId 형식과 일관성 유지

ClinicalSessionStore:
  - lastSubject: String 추가 (다음 측정 자동 prefill)
  - startMeasurement에서 저장

JSON 저장:
  - meta.json + measurement.json의 meta 블록에 "subject" 필드 추가
  - 비어있으면 필드 자체 생략 (기존 호환)

labdb payload:
  - params.subject 필드 추가 (subject_type과 함께)

UI (ClinicalHomeView):
  - SubjectType segmented 아래에 OutlinedTextField
  - 라벨: 'Subject (선택) — 예: 500mL, S001'
  - IME action Done + onDone hide
  - 마지막 입력 유지 (lastSubject prefill)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-09 17:26:37 +09:00
parent 82ba3bbcf6
commit 7fa18ec05a
4 changed files with 44 additions and 3 deletions
@@ -47,8 +47,12 @@ data class ClinicalSession(
val step: ClinicalStep,
val examiner: String = "",
val notes: String = "",
// 측정 대상 분류 (회의 결정: Phantom/Human/ETC 버튼 — subject ID 자유 입력 대체)
// 측정 대상 분류 (회의: Phantom/Human/ETC 버튼)
val subjectType: SubjectType = SubjectType.PHANTOM,
// 카테고리 내 추가 식별자 (회의 추가 결정: optional)
// 예: "500mL", "S001", "small phantom v2" 등
// 비어있으면 folderName에 포함 안 됨
val subject: String = "",
val trueVolumeMl: Double? = null, // 외부 초음파 측정기 참값 (mL)
val abdomenThicknessMm: Double? = null, // 복부 두께 측정기 참값 (mm)
val startedAt: Long = System.currentTimeMillis(),
@@ -56,9 +60,22 @@ data class ClinicalSession(
) {
private val folderFmt = SimpleDateFormat("yyyy-MM-dd_HHmmss", Locale.US)
/** "PHANTOM_VBT26050202_SUPINE_ALIGN_0CM_2026-05-28_14-30-15" */
/** "PHANTOM-500mL_VBT26050202_SUPINE_ALIGN_0CM_2026-05-28_14-30-15"
* subject 비어있으면 "PHANTOM_VBT...". 폴더명 안전한 문자만 (특수문자 → '-'). */
val folderName: String
get() = "${subjectType.name}_${deviceName}_${posture.name}_${step.name}_${folderFmt.format(Date(startedAt))}"
get() = buildString {
append(subjectType.name)
if (subject.isNotBlank()) {
append('-')
// 폴더명/파일명 안전 문자만 — testId 형식과도 일관 (^[A-Za-z0-9_-]$)
append(subject.replace(Regex("[^A-Za-z0-9_-]"), "-"))
}
append('_')
append(deviceName); append('_')
append(posture.name); append('_')
append(step.name); append('_')
append(folderFmt.format(Date(startedAt)))
}
/** clinical_label 컬럼/필드 값 (라벨링 자동) */
val label: String