diff --git a/apps/web/app/dashboard/page.tsx b/apps/web/app/dashboard/page.tsx index 2275b4f..c868212 100644 --- a/apps/web/app/dashboard/page.tsx +++ b/apps/web/app/dashboard/page.tsx @@ -1,3 +1,4 @@ +import { CtrsLegend } from "../../components/CtrsLegend"; import { PatientListItem } from "../../components/PatientListItem"; import { APIException, listPatients, type PatientListItem as Item } from "../../lib/api"; @@ -49,13 +50,16 @@ export default async function DashboardPage() { {patients.length === 0 ? (

아직 등록된 환자가 없어요.

) : ( - +
+ + +
)} ); diff --git a/apps/web/components/CtrsBadge.tsx b/apps/web/components/CtrsBadge.tsx new file mode 100644 index 0000000..c3f2493 --- /dev/null +++ b/apps/web/components/CtrsBadge.tsx @@ -0,0 +1,20 @@ +import { CTRS_META, ctrsFromLevel, type RiskLevel } from "../lib/tokens"; + +/** + * 환자 목록용 CTRS(위기분류척도) 단계 배지 — `CTRS N · 라벨` 형식. + * safety risk level을 위험성(Rating A) 기준 CTRS 단계로 환산해 표기하며, + * RiskEvent가 없는 환자도 항상 `CTRS 5 · 안정`으로 표시한다(전원 단계 표기). + */ +export function CtrsBadge({ level }: { level: RiskLevel | null | undefined }) { + const stage = ctrsFromLevel(level); + const { label, badge } = CTRS_META[stage]; + return ( + + + CTRS {stage} · {label} + + ); +} diff --git a/apps/web/components/CtrsLegend.tsx b/apps/web/components/CtrsLegend.tsx new file mode 100644 index 0000000..2b6714e --- /dev/null +++ b/apps/web/components/CtrsLegend.tsx @@ -0,0 +1,73 @@ +import { CTRS_META, type CtrsStage } from "../lib/tokens"; + +/** + * CTRS(위기분류척도, Crisis Triage Rating Scale) 참고 범례. + * 환자 목록의 CTRS 단계 배지는 **위험성(Rating A)** 기준으로 자동 산출된다. + * 지지체계(Rating B)는 별도 축으로, 현재 자동 산출 대상은 아니며 임상 참고용. + */ + +// Rating A: 위험성(Dangerousness) — 배지 단계와 직접 대응. +const RATING_A: Record = { + 1: "자살·자해 사고/관련 환청, 현병력 중 자살시도, 예측 불가한 폭력·충동", + 2: "자살 사고·행동으로 스스로 고통, 폭력·충동 과거력(현재 징후 없음)", + 3: "자·타해 사고를 양가적으로 표현하거나 비효과적 몸짓만 있음", + 4: "자·타해 사고/행동이 부분적·기왕력, 행동조절 욕구 분명·조절 가능", + 5: "자·타해 사고나 행동의 과거력·위험 없음", +}; + +// Rating B: 지지체계(Support System) — 참고 축. +const RATING_B: Record = { + 1: "가족·친구 등 지지체계 전무, 기관의 즉각 지지도 불가", + 2: "동원 가능한 지지체계는 있으나 효과가 제한적", + 3: "잠재적 지지체계는 있으나 제대로 기능하기 어려움", + 4: "관심 있는 지지체계 있으나 지지 제공 능력·의지 다소 불명확", + 5: "관심 있는 지지체계가 지지 제공 능력·의지를 갖춤", +}; + +const STAGES: CtrsStage[] = [1, 2, 3, 4, 5]; + +export function CtrsLegend() { + return ( + + ); +} diff --git a/apps/web/components/PatientListItem.tsx b/apps/web/components/PatientListItem.tsx index 4156203..2531c8b 100644 --- a/apps/web/components/PatientListItem.tsx +++ b/apps/web/components/PatientListItem.tsx @@ -1,7 +1,7 @@ import Link from "next/link"; import type { PatientListItem as PatientListItemT } from "../lib/api"; -import { RiskBadge } from "./RiskBadge"; +import { CtrsBadge } from "./CtrsBadge"; function relative(iso: string | null): string { if (!iso) return "—"; @@ -38,7 +38,8 @@ export function PatientListItem({ item }: { item: PatientListItemT }) {

- {item.latestRisk ? : null} + {/* CTRS 위기분류척도 단계 — 전원 표기(위험신호 없으면 5·안정). */} + {item.riskEventCount > 0 ? ( 위험 이벤트 {item.riskEventCount}건 diff --git a/apps/web/lib/tokens.ts b/apps/web/lib/tokens.ts index 7dc2fd9..59074e5 100644 --- a/apps/web/lib/tokens.ts +++ b/apps/web/lib/tokens.ts @@ -44,3 +44,44 @@ export const riskBadge = { } as const; export type RiskLevel = keyof typeof riskColor; + +/** + * CTRS(위기분류척도, Crisis Triage Rating Scale) 단계 표기. + * 대시보드 환자 목록은 safety risk level을 위험성(Rating A) 기준 CTRS 단계로 환산해 + * 표기한다: critical→1(고위험) … RiskEvent 없음→5(안정). (앱 서버 `_RISK_TO_CTRS`와 동일) + */ +export type CtrsStage = 1 | 2 | 3 | 4 | 5; + +export function ctrsFromLevel(level: RiskLevel | null | undefined): CtrsStage { + switch (level) { + case "critical": + return 1; + case "high": + return 2; + case "medium": + return 3; + case "low": + return 4; + default: + return 5; // RiskEvent 없음 = 위험 신호 없음 + } +} + +export const CTRS_META: Record< + CtrsStage, + { label: string; badge: { bg: string; border: string; text: string; dot: string } } +> = { + 1: { label: "고위험", badge: riskBadge.critical }, + 2: { label: "위험", badge: riskBadge.high }, + 3: { label: "주의", badge: riskBadge.medium }, + 4: { label: "관찰", badge: riskBadge.low }, + 5: { + label: "안정", + badge: { + bg: "bg-surface-elevated", + border: "border-border", + text: "text-text-secondary", + dot: "bg-faint", + }, + }, +};