/* Generated from patient-service-desk-v3.js for direct file:// opening. */ (() => { // docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.state.mjs function createInitialState({ activePatientId = "patient-zhang-san", demoNow = "2026-07-03T09:00:00+08:00" } = {}) { return { activeTab: "home", activePatientId, demoNow, appliedProjectionFixtureIds: [], activeAgentTaskProjection: null, patientWorkItems: [], journeyProjections: [], reportSourceProjections: {}, reportFeedback: [], reportFilters: { family: "ALL", status: "ALL" }, resultSnapshotProjections: {}, commandProjections: {}, messages: [], consents: {}, consentScopeBindings: {}, overlays: { commandId: null, consentId: null, consentScope: null, reportId: null, reportView: null, reportUnavailableReason: null, reportExpanded: false, reportFeedbackOpen: false, reportFeedbackSubmitted: false, reportServiceNotice: null, appointmentId: null, journeyView: null, scenarioPanelOpen: false } }; } var deepFreeze = (value) => { if (value && typeof value === "object" && !Object.isFrozen(value)) { Object.freeze(value); Object.values(value).forEach(deepFreeze); } return value; }; var isRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value); var reportIdPattern = /^[^\s\u0000-\u001F\u007F]{1,128}$/; var reportHashPattern = /^[^\s\u0000-\u001F\u007F]{1,256}$/; var reportSourceStatuses = /* @__PURE__ */ new Set(["FINAL", "PRELIMINARY"]); var reportFamilies = /* @__PURE__ */ new Set(["LAB", "EXAM"]); var reportTypes = /* @__PURE__ */ new Set(["BLOOD_ROUTINE", "IMAGING"]); var reportVerificationStatuses = /* @__PURE__ */ new Set(["VERIFIED", "NEED_REVIEW"]); var bloodRoutineReportFixture = deepFreeze({ reportId: "report-blood-20260702", family: "LAB", reportType: "BLOOD_ROUTINE", title: "\u8840\u5E38\u89C4", hospitalName: "\u7A7A\u6D77\u533B\u9662", departmentName: "\u68C0\u9A8C\u79D1", issuedAt: "2026-07-03 09:30", sourceStatus: "FINAL", interpretationStatus: "NOT_REQUESTED", verificationStatus: "VERIFIED", sourceVersion: 1, sourceHash: "sha256:blood-v1", readStatus: "UNREAD", metrics: [ { code: "WBC", name: "\u767D\u7EC6\u80DE\u8BA1\u6570", value: 11.2, unit: "10^9/L", referenceRange: "3.5\u20139.5", sourceFlag: "HIGH" } ] }); var registrationDemoText = "\u6211\u60F3\u6302\u660E\u5929\u795E\u7ECF\u5185\u79D1\u674E\u660E\u4E3B\u4EFB\u7684\u53F7"; var registrationResultRef = "result-slot-001"; var registrationResultVersion = 1; var registrationItems = deepFreeze([ { candidateId: "candidate-slot-0930", visitDate: "2026-07-03", timePeriod: "\u4E0A\u5348", visitTime: "09:30", departmentName: "\u795E\u7ECF\u5185\u79D1", doctorName: "\u674E\u660E", doctorTitle: "\u4E3B\u4EFB\u533B\u5E08", remainingSlots: 3, fee: "30\u5143" }, { candidateId: "candidate-slot-1030", visitDate: "2026-07-03", timePeriod: "\u4E0A\u5348", visitTime: "10:30", departmentName: "\u795E\u7ECF\u5185\u79D1", doctorName: "\u674E\u660E", doctorTitle: "\u4E3B\u4EFB\u533B\u5E08", remainingSlots: 1, fee: "30\u5143" }, { candidateId: "candidate-slot-1430", visitDate: "2026-07-03", timePeriod: "\u4E0B\u5348", visitTime: "14:30", departmentName: "\u795E\u7ECF\u5185\u79D1", doctorName: "\u674E\u660E", doctorTitle: "\u4E3B\u4EFB\u533B\u5E08", remainingSlots: 5, fee: "30\u5143" } ]); var registrationResultText = [ `\u5DF2\u4E3A\u4F60\u627E\u5230 ${registrationItems[0].visitDate} ${registrationItems[0].departmentName}${registrationItems[0].doctorName}${registrationItems[0].doctorTitle}\u7684 ${registrationItems.length} \u4E2A\u53F7\u6E90\uFF1A`, ...registrationItems.map((item) => `${item.visitDate} ${item.timePeriod} ${item.visitTime}\uFF0C${item.departmentName}\uFF0C${item.doctorName}${item.doctorTitle}\uFF0C\u4F59\u53F7 ${item.remainingSlots}\uFF0C\u6302\u53F7\u8D39 ${item.fee}\uFF1B`), "\u8BF7\u9009\u62E9\u4E00\u4E2A\u53F7\u6E90\u3002" ].join(""); var nextMessageId = (messages, role) => { const usedIds = new Set( messages.filter((message) => message && typeof message === "object").map(({ id }) => id) ); let sequence = messages.length + 1; while (usedIds.has(`message-${role}-${sequence}`)) { sequence += 1; } return `message-${role}-${sequence}`; }; var simulateRegistrationQueryBackendFixture = (interaction) => { if (interaction?.text !== registrationDemoText) { return { type: "NO_RESULT", text: interaction?.text ? "\u6682\u65F6\u6CA1\u6709\u627E\u5230\u5339\u914D\u7ED3\u679C\u3002\u4F60\u53EF\u4EE5\u6362\u4E2A\u8BF4\u6CD5\uFF0C\u8BD5\u8BD5\u667A\u80FD\u5BFC\u8BCA\uFF0C\u6216\u8F6C\u4EBA\u5DE5\u670D\u52A1\u3002" : "\u8BF7\u8F93\u5165\u60F3\u529E\u7406\u7684\u5C31\u533B\u670D\u52A1\u3002\u4F60\u4E5F\u53EF\u4EE5\u8BD5\u8BD5\u667A\u80FD\u5BFC\u8BCA\u6216\u4EBA\u5DE5\u670D\u52A1\u3002" }; } return { type: "REGISTRATION_CANDIDATES", task: { taskId: "agent-task-registration-001", type: "REGISTRATION", stage: "CANDIDATE_SELECTION", constraints: { departmentName: "\u795E\u7ECF\u5185\u79D1", doctorName: "\u674E\u660E", doctorTitle: "\u4E3B\u4EFB\u533B\u5E08", visitDate: "2026-07-03" }, missingFields: [], activeResultRef: registrationResultRef }, result: { resultRef: registrationResultRef, resultVersion: registrationResultVersion, expiresAt: "2026-07-03T10:00:00+08:00", text: registrationResultText, items: registrationItems.map((item) => ({ ...item })) } }; }; var applyRegistrationQueryResponseFixture = (state, interaction, fixture) => { const messages = Array.isArray(state.messages) ? state.messages : []; const userMessage = interaction.text ? [{ id: nextMessageId(messages, "user"), role: "user", text: interaction.text }] : []; const assistantMessage = { id: nextMessageId([...messages, ...userMessage], "assistant"), role: "assistant", text: fixture.text ?? fixture.result?.text, ...fixture.result?.resultRef ? { resultRef: fixture.result.resultRef } : {} }; if (fixture.type !== "REGISTRATION_CANDIDATES") { return { ...state, activeTab: "assistant", messages: [...messages, ...userMessage, assistantMessage] }; } return { ...state, activeTab: "assistant", activeAgentTaskProjection: fixture.task, resultSnapshotProjections: { ...state.resultSnapshotProjections ?? {}, [fixture.result.resultRef]: fixture.result }, messages: [...messages, ...userMessage, assistantMessage] }; }; function submitInteraction(state, text) { if (!state || typeof state !== "object" || Array.isArray(state)) { return state; } const normalizedText = typeof text === "string" ? text.trim() : ""; const interaction = { interactionType: "USER_MESSAGE", text: normalizedText }; const responseFixture = simulateRegistrationQueryBackendFixture( interaction ); return applyRegistrationQueryResponseFixture( state, interaction, responseFixture ); } function buildCandidateSelectionInteraction(state, candidateSelection, now) { const task = state?.activeAgentTaskProjection; const resultRef = task?.activeResultRef; const result = typeof resultRef === "string" ? state?.resultSnapshotProjections?.[resultRef] : null; const normalizedSelection = typeof candidateSelection === "string" ? candidateSelection.trim() : candidateSelection; const candidateId = normalizedSelection === "\u9009\u7B2C\u4E00\u4E2A" ? result?.items?.[0]?.candidateId : normalizedSelection; const expiresAt = Date.parse(result?.expiresAt); const evaluatedAt = Date.parse(now ?? state?.demoNow); const isExpired = !Number.isFinite(expiresAt) || !Number.isFinite(evaluatedAt) || expiresAt <= evaluatedAt; const hasCandidate = Array.isArray(result?.items) && result.items.some( (item) => item?.candidateId === candidateId ); if (task?.type !== "REGISTRATION" || task.stage !== "CANDIDATE_SELECTION" || result?.resultRef !== resultRef || !Number.isInteger(result?.resultVersion) || result.resultVersion <= 0 || isExpired || !hasCandidate) { return null; } return { interactionType: "SELECT_CANDIDATE", resultRef, resultVersion: result.resultVersion, candidateId }; } function applyCandidateSelectionResponseFixture(state, fixture) { if (!state || typeof state !== "object" || !fixture?.id) { return state; } const appliedIds = Array.isArray(state.appliedProjectionFixtureIds) ? state.appliedProjectionFixtureIds : []; if (appliedIds.includes(fixture.id)) { return state; } const task = state?.activeAgentTaskProjection; const result = task?.activeResultRef ? state?.resultSnapshotProjections?.[task.activeResultRef] : null; const isActiveSelection = task?.type === "REGISTRATION" && task.stage === "CANDIDATE_SELECTION" && result?.resultRef === task.activeResultRef; if (!isActiveSelection) { return state; } const canonicalErrors = /* @__PURE__ */ new Set([ "RESULT_VERSION_CONFLICT", "RESULT_EXPIRED", "SLOT_UNAVAILABLE" ]); const validation = fixture.validation ?? {}; const derivedError = validation.versionMatched === false ? "RESULT_VERSION_CONFLICT" : validation.notExpired === false ? "RESULT_EXPIRED" : validation.realtimeAvailable === false || validation.l1LockSucceeded === false ? "SLOT_UNAVAILABLE" : null; const baseState = { ...state, appliedProjectionFixtureIds: [...appliedIds, fixture.id] }; const evaluatedAt = Date.parse(state.demoNow); const snapshotExpiresAt = Date.parse(result.expiresAt); const snapshotNotExpired = Number.isFinite(evaluatedAt) && Number.isFinite(snapshotExpiresAt) && snapshotExpiresAt > evaluatedAt; const lockExpiresAt = Date.parse(fixture.lock?.expiresAt); const lockIdValid = typeof fixture.lock?.lockId === "string" && fixture.lock.lockId.trim().length > 0; const lockExpiryValid = Number.isFinite(evaluatedAt) && Number.isFinite(lockExpiresAt) && lockExpiresAt > evaluatedAt; const candidateExists = Array.isArray(result?.items) && result.items.some( (item) => item?.candidateId === fixture.candidateId ); const validationPassed = [ "tenantMatched", "patientMatched", "sessionMatched", "versionMatched", "notExpired", "realtimeAvailable", "l1LockSucceeded" ].every((key) => validation[key] === true); const successIsValid = fixture.outcome === "SUCCESS" && fixture.resultRef === result.resultRef && fixture.resultVersion === result.resultVersion && candidateExists && validationPassed && snapshotNotExpired && lockIdValid && lockExpiryValid; if (!successIsValid) { const errorCode = canonicalErrors.has(fixture.errorCode) ? fixture.errorCode : derivedError ?? (!snapshotNotExpired ? "RESULT_EXPIRED" : !lockIdValid && fixture.outcome === "SUCCESS" ? "SLOT_UNAVAILABLE" : !lockExpiryValid && fixture.outcome === "SUCCESS" ? "RESULT_EXPIRED" : "UNKNOWN_SELECTION_ERROR"); const unavailableAdvice = errorCode === "SLOT_UNAVAILABLE" ? " \u5F53\u524D\u53F7\u6E90\u5DF2\u65E0\u53F7\uFF0C\u53EF\u67E5\u770B\u5176\u4ED6\u65F6\u6BB5\u6216\u533B\u751F\u3002" : ""; const messages2 = Array.isArray(state.messages) ? state.messages : []; return { ...baseState, activeAgentTaskProjection: { ...task, stage: "REQUERY_REQUIRED", activeResultRef: null }, messages: [ ...messages2, { id: nextMessageId(messages2, "assistant"), role: "assistant", text: `\u7ED3\u679C\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u91CD\u65B0\u67E5\u8BE2\u3002${unavailableAdvice}` } ] }; } const messages = Array.isArray(state.messages) ? state.messages : []; return { ...baseState, activeAgentTaskProjection: { ...task, stage: "AWAITING_REGISTRATION_CONFIRMATION", selectedCandidateId: fixture.candidateId, lock: { ...fixture.lock } }, messages: [ ...messages, { id: nextMessageId(messages, "assistant"), role: "assistant", text: "\u9501\u53F7\u6210\u529F\uFF0C\u8BF7\u5728\u9501\u5B9A\u65F6\u95F4\u5185\u5B8C\u6210\u4E8C\u6B21\u786E\u8BA4\u540E\u6302\u53F7\u3002" } ] }; } var commandStatuses = /* @__PURE__ */ new Set([ "PREPARED", "AWAITING_CONFIRMATION", "EXECUTING", "SUCCEEDED", "FAILED", "EXPIRED", "UNKNOWN", "REJECTED" ]); var commandTransitions = { L1: { PREPARED: /* @__PURE__ */ new Set(["EXECUTING"]), EXECUTING: /* @__PURE__ */ new Set(["SUCCEEDED", "FAILED", "UNKNOWN"]), UNKNOWN: /* @__PURE__ */ new Set(["SUCCEEDED", "FAILED"]) }, L2: { PREPARED: /* @__PURE__ */ new Set(["AWAITING_CONFIRMATION"]), AWAITING_CONFIRMATION: /* @__PURE__ */ new Set([ "EXECUTING", "REJECTED", "EXPIRED" ]), EXECUTING: /* @__PURE__ */ new Set(["SUCCEEDED", "FAILED", "UNKNOWN"]), UNKNOWN: /* @__PURE__ */ new Set(["SUCCEEDED", "FAILED"]) } }; var initialCommandStatuses = { L1: /* @__PURE__ */ new Set(["PREPARED", "UNKNOWN"]), L2: /* @__PURE__ */ new Set(["PREPARED", "AWAITING_CONFIRMATION", "UNKNOWN"]) }; var commandFixtureError = (message) => { throw new Error(`Command projection fixture invalid: ${message}`); }; var legacyAppointmentResult = { type: "APPOINTMENT_CREATED", eventId: "appointment-created-001", appointmentId: "appointment-001", patientId: "patient-zhang-san", summary: { visitDate: "2026-07-03", visitTime: "09:30", departmentName: "\u795E\u7ECF\u5185\u79D1", doctorName: "\u674E\u660E", doctorTitle: "\u4E3B\u4EFB\u533B\u5E08", fee: "30\u5143" } }; var applyAppointmentCreatedProjection = (state, fixture) => { const result = fixture.result ?? (fixture.resultFixtureId === "appointment-created-001" ? legacyAppointmentResult : null); if (!result || result.type !== "APPOINTMENT_CREATED") { return state; } const eventId = result.eventId ?? fixture.resultFixtureId; if (typeof eventId !== "string" || !eventId || typeof result.appointmentId !== "string" || !result.appointmentId) { commandFixtureError("appointment result identifiers are required"); } if (state.appliedProjectionFixtureIds.includes(eventId)) { return state; } const summary = result.summary ?? {}; const doctor = `${summary.doctorName ?? ""}${summary.doctorTitle ?? ""}`; return { ...state, appliedProjectionFixtureIds: [ ...state.appliedProjectionFixtureIds, eventId ], patientWorkItems: [ ...state.patientWorkItems, { id: `work-item-${result.appointmentId}`, appointmentId: result.appointmentId, patientId: result.patientId, type: "APPOINTMENT", status: "UPCOMING", stage: "WAITING_ARRIVAL", priority: 80, title: `${summary.departmentName ?? "\u95E8\u8BCA"}\u9884\u7EA6\u6210\u529F`, description: `${summary.visitDate ?? ""} ${summary.visitTime ?? ""} \xB7 ${doctor} \xB7 ${summary.fee ?? ""}`, fee: summary.fee, primaryAction: null, secondaryAction: null, expiresAt: null } ], journeyProjections: [ ...state.journeyProjections, { id: `journey-${result.appointmentId}`, stage: "WAITING_ARRIVAL", title: "\u5F85\u5230\u9662", appointmentId: result.appointmentId, patientId: result.patientId } ] }; }; function applyCommandProjectionFixture(state, fixture) { if (!state || typeof state !== "object" || Array.isArray(state)) { commandFixtureError("state is required"); } if (!fixture || typeof fixture !== "object" || Array.isArray(fixture)) { commandFixtureError("fixture is required"); } const { id, commandId, status } = fixture; if (typeof id !== "string" || !id.trim()) { commandFixtureError("id is required"); } if (typeof commandId !== "string" || !commandId.trim()) { commandFixtureError("commandId is required"); } if (status === "COMPLETED") { commandFixtureError("COMPLETED is not a Command status"); } if (!commandStatuses.has(status)) { commandFixtureError(`unknown status ${String(status)}`); } const appliedIds = Array.isArray(state.appliedProjectionFixtureIds) ? state.appliedProjectionFixtureIds : []; if (appliedIds.includes(id)) { return state; } const current = state.commandProjections?.[commandId]; const riskLevel = fixture.riskLevel ?? current?.riskLevel ?? "L2"; if (riskLevel !== "L1" && riskLevel !== "L2") { commandFixtureError(`unknown riskLevel ${String(riskLevel)}`); } if (current && current.riskLevel !== riskLevel) { commandFixtureError("riskLevel cannot change"); } const version = fixture.version ?? current?.version; if (version !== void 0 && (!Number.isInteger(version) || version <= 0)) { commandFixtureError("version must be a positive integer"); } if (!current && !initialCommandStatuses[riskLevel].has(status)) { commandFixtureError( `illegal initial ${riskLevel} status ${status}` ); } if (current) { const isFinalBusinessSnapshot = riskLevel === "L2" && current.status === "AWAITING_CONFIRMATION" && status === "SUCCEEDED" && fixture.resultFixtureId === "appointment-created-001" && fixture.result === void 0 && fixture.version === void 0; const transitionAllowed = commandTransitions[riskLevel][current.status]?.has(status); if (!isFinalBusinessSnapshot && (!Number.isInteger(fixture.version) || !Number.isInteger(current.version) || fixture.version <= current.version)) { commandFixtureError("version must explicitly increase"); } if (!transitionAllowed && !isFinalBusinessSnapshot) { commandFixtureError( `illegal ${riskLevel} transition ${current.status} -> ${status}` ); } } const projection = { ...current, commandId, status, riskLevel, ...version === void 0 ? {} : { version }, ...fixture.details === void 0 ? {} : { details: structuredClone(fixture.details) }, ...fixture.resultFixtureId === void 0 ? {} : { resultFixtureId: fixture.resultFixtureId }, ...fixture.result === void 0 ? {} : { result: structuredClone(fixture.result) } }; let nextState = { ...state, appliedProjectionFixtureIds: [...appliedIds, id], commandProjections: { ...state.commandProjections ?? {}, [commandId]: projection }, overlays: { ...state.overlays, commandId } }; if (status === "SUCCEEDED" && (fixture.result?.type === "APPOINTMENT_CREATED" || fixture.resultFixtureId === "appointment-created-001")) { nextState = applyAppointmentCreatedProjection(nextState, fixture); } return nextState; } function buildCommandConfirmationRequest(state, commandId, { channel, idempotencyKey } = {}) { const command = state?.commandProjections?.[commandId]; if (!command) { throw new Error("Command \u4E0D\u5B58\u5728\uFF0C\u65E0\u6CD5\u786E\u8BA4"); } if (command.status === "UNKNOWN") { throw new Error("\u7ED3\u679C\u786E\u8BA4\u4E2D\uFF0C\u8BF7\u52FF\u91CD\u590D\u64CD\u4F5C"); } if (command.status === "EXPIRED") { throw new Error("Command \u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u67E5\u8BE2\u53F7\u6E90"); } if (command.status !== "AWAITING_CONFIRMATION") { throw new Error(`\u5F53\u524D\u72B6\u6001 ${command.status} \u4E0D\u5141\u8BB8\u91CD\u590D\u786E\u8BA4`); } if (!Number.isInteger(command.version) || command.version <= 0) { throw new Error("Command version \u65E0\u6548"); } if (channel !== "CARD") { throw new Error("\u786E\u8BA4\u6E20\u9053\u4E0D\u53D7\u652F\u6301"); } if (typeof idempotencyKey !== "string" || !idempotencyKey.trim()) { throw new Error("\u5E42\u7B49\u952E\u4E0D\u80FD\u4E3A\u7A7A"); } return { path: `/api/v2/commands/${encodeURIComponent(commandId)}/confirm`, method: "POST", commandId, body: { commandVersion: command.version, confirmation: { channel, explicit: true } }, headers: { "X-Emoon-Idempotency-Key": idempotencyKey } }; } function buildCommandRejectionRequest(state, commandId, { reason, idempotencyKey } = {}) { const command = state?.commandProjections?.[commandId]; if (!command) { throw new Error("Command \u4E0D\u5B58\u5728\uFF0C\u65E0\u6CD5\u62D2\u7EDD"); } if (command.status !== "AWAITING_CONFIRMATION") { throw new Error(`\u5F53\u524D\u72B6\u6001 ${command.status} \u4E0D\u5141\u8BB8\u62D2\u7EDD`); } if (!Number.isInteger(command.version) || command.version <= 0) { throw new Error("Command version \u65E0\u6548"); } if (typeof idempotencyKey !== "string" || !idempotencyKey.trim()) { throw new Error("\u5E42\u7B49\u952E\u4E0D\u80FD\u4E3A\u7A7A"); } return { path: `/api/v2/commands/${encodeURIComponent(commandId)}/reject`, method: "POST", commandId, body: { commandVersion: command.version, ...typeof reason === "string" && reason.trim() ? { reason: reason.trim() } : {} }, headers: { "X-Emoon-Idempotency-Key": idempotencyKey } }; } var statusRank = { ACTION_REQUIRED: 0, IN_PROGRESS: 1, UPCOMING: 2, COMPLETED: 3 }; var reportInterpretationProjectionFixture = deepFreeze({ resultRef: "result-report-interpretation-001", resultVersion: 1, interpretation: { headline: "3 \u9879\u6307\u6807\u8F7B\u5EA6\u5F02\u5E38", summary: "\u8FD9\u4EFD\u62A5\u544A\u6709 3 \u9879\u6307\u6807\u8D85\u51FA\u53C2\u8003\u8303\u56F4\uFF0C\u53D8\u5316\u5E45\u5EA6\u8F83\u5C0F\uFF0C\u9700\u8981\u7ED3\u5408\u8FD1\u671F\u75C7\u72B6\u548C\u75C5\u53F2\u7531\u533B\u751F\u7EFC\u5408\u5224\u65AD\u3002", safety: "\u672C\u89E3\u91CA\u4EC5\u7528\u4E8E\u5E2E\u52A9\u7406\u89E3\u62A5\u544A\u6307\u6807\uFF0C\u4E0D\u7528\u4E8E\u5224\u65AD\u75BE\u75C5\u6216\u66FF\u4EE3\u533B\u751F\u610F\u89C1\u3002\u5982\u6709\u660E\u663E\u4E0D\u9002\uFF0C\u8BF7\u53CA\u65F6\u8054\u7CFB\u533B\u52A1\u4EBA\u5458\u3002", highlights: [ { name: "\u767D\u7EC6\u80DE\u8BA1\u6570", value: "11.2", flag: "\u504F\u9AD8" }, { name: "\u4E2D\u6027\u7C92\u7EC6\u80DE\u6BD4\u4F8B", value: "78%", flag: "\u504F\u9AD8" }, { name: "\u6DCB\u5DF4\u7EC6\u80DE\u6BD4\u4F8B", value: "18%", flag: "\u504F\u4F4E" } ], explanations: [ { indicator: "\u767D\u7EC6\u80DE 11.2 \xD710\u2079/L", explanation: "\u8F7B\u5EA6\u9AD8\u4E8E\u62A5\u544A\u6240\u793A\u53C2\u8003\u8303\u56F4\uFF0C\u5355\u9879\u53D8\u5316\u4E0D\u80FD\u72EC\u7ACB\u8BF4\u660E\u5177\u4F53\u539F\u56E0\u3002", commonFactors: "\u8FD1\u671F\u611F\u67D3\u3001\u7761\u7720\u4E0D\u8DB3\u3001\u8FD0\u52A8\u6216\u60C5\u7EEA\u7D27\u5F20\u7B49\u3002" }, { indicator: "\u4E2D\u6027\u7C92\u7EC6\u80DE\u6BD4\u4F8B 78%", explanation: "\u6BD4\u4F8B\u8F7B\u5EA6\u5347\u9AD8\uFF0C\u9700\u7ED3\u5408\u767D\u7EC6\u80DE\u603B\u6570\u548C\u5F53\u524D\u75C7\u72B6\u5224\u65AD\u3002", commonFactors: "\u7EC6\u83CC\u611F\u67D3\u3001\u6025\u6027\u708E\u75C7\u6216\u751F\u7406\u5E94\u6FC0\u7B49\u3002" }, { indicator: "\u6DCB\u5DF4\u7EC6\u80DE\u6BD4\u4F8B 18%", explanation: "\u6BD4\u4F8B\u8F7B\u5EA6\u504F\u4F4E\uFF0C\u53EF\u80FD\u4E0E\u4E2D\u6027\u7C92\u7EC6\u80DE\u6BD4\u4F8B\u5347\u9AD8\u540C\u65F6\u51FA\u73B0\u3002", commonFactors: "\u611F\u67D3\u6062\u590D\u671F\u3001\u538B\u529B\u6216\u4E2A\u4F53\u77ED\u671F\u6CE2\u52A8\u7B49\u3002" } ], canDo: [ "\u67E5\u770B\u5E76\u4FDD\u5B58\u533B\u9662\u539F\u59CB\u62A5\u544A\u3002", "\u7ED3\u5408\u8FD1\u671F\u75C7\u72B6\u548C\u65E2\u5F80\u60C5\u51B5\uFF0C\u5411\u5F00\u5355\u533B\u751F\u54A8\u8BE2\u3002", "\u5982\u6709\u660E\u663E\u4E0D\u9002\uFF0C\u53CA\u65F6\u8054\u7CFB\u533B\u52A1\u4EBA\u5458\u3002" ], evidence: [ "\u533B\u9662\u539F\u59CB\u62A5\u544A\u4E2D\u7684\u6307\u6807\u7ED3\u679C\u3001\u5355\u4F4D\u3001\u53C2\u8003\u8303\u56F4\u548C\u5F02\u5E38\u6807\u8BB0\u3002", "\u533B\u9662\u5DF2\u5BA1\u6838\u7684\u7EC8\u7248\u62A5\u544A\u3002" ] } }); var reportConsentId = (reportId) => `consent-ai-${reportId}`; var encodeReportId = (reportId) => String(reportId).replace( /[^A-Za-z0-9._-]/g, (character) => `~${character.charCodeAt(0).toString(16).padStart(4, "0")}` ); var reportResultSnapshotId = (reportId) => `result-report-interpretation-${encodeReportId(reportId)}`; var reportFeedbackCategories = /* @__PURE__ */ new Set([ "HELPFUL", "METRIC_INACCURATE", "HARD_TO_UNDERSTAND", "DIFFERS_FROM_DOCTOR", "OTHER" ]); var readReportIssuedFixture = (fixture) => { if (fixture.payload !== void 0 && !isRecord(fixture.payload)) { return null; } const payload = fixture.payload ?? {}; const isExamination = payload.family === "EXAM"; const report = { ...bloodRoutineReportFixture, ...payload, interpretationStatus: "NOT_REQUESTED", metrics: Array.isArray(payload.metrics) ? payload.metrics : isExamination ? [] : bloodRoutineReportFixture.metrics }; if (typeof report.reportId !== "string" || !reportIdPattern.test(report.reportId) || !Number.isInteger(report.sourceVersion) || report.sourceVersion <= 0 || typeof report.sourceHash !== "string" || !reportHashPattern.test(report.sourceHash) || !reportSourceStatuses.has(report.sourceStatus) || !reportFamilies.has(report.family) || !reportTypes.has(report.reportType) || !reportVerificationStatuses.has(report.verificationStatus) || report.family === "LAB" && report.reportType !== "BLOOD_ROUTINE" || report.family === "EXAM" && report.reportType !== "IMAGING") { return null; } return deepFreeze(structuredClone(report)); }; var hasValidReportConsent = (state, reportId) => { if (typeof reportId !== "string" || reportId.length === 0 || !isRecord(state?.consents) || !isRecord(state?.consentScopeBindings)) { return false; } const consentId = reportConsentId(reportId); const consent = Object.hasOwn(state.consents, consentId) ? state.consents[consentId] : null; const binding = Object.hasOwn(state.consentScopeBindings, consentId) ? state.consentScopeBindings[consentId] : null; const expiresAt = Date.parse(consent?.expiresAt); const evaluatedAt = Date.parse(state?.demoNow); return consent?.id === consentId && consent.status === "GRANTED" && Number.isFinite(expiresAt) && Number.isFinite(evaluatedAt) && expiresAt > evaluatedAt && binding?.patientId === state?.activePatientId && binding?.reportId === reportId; }; var selectValidReportResult = (state, reportId) => { if (typeof reportId !== "string" || reportId.length === 0) { return null; } const resultRef = reportResultSnapshotId(reportId); const reportSources = state?.reportSourceProjections; const results = state?.resultSnapshotProjections; const report = isRecord(reportSources) && Object.hasOwn(reportSources, reportId) ? reportSources[reportId] : null; const result = isRecord(results) && Object.hasOwn(results, resultRef) ? results[resultRef] : null; const hasScopedTask = Array.isArray(state?.patientWorkItems) && state.patientWorkItems.some((item) => item?.type === "REPORT_REVIEW" && item.reportId === reportId); return isRecord(report) && report.reportId === reportId && report.interpretationStatus === "READY" && hasScopedTask && hasValidReportConsent(state, reportId) && evaluateReportInterpretationGate(state, reportId).allowed && isRecord(result) && result.resultRef === resultRef && result.reportId === reportId && result.sourceVersion === report.sourceVersion && result.sourceHash === report.sourceHash && Number.isInteger(result.resultVersion) && result.resultVersion > 0 && result.valid === true && isRecord(result.interpretation) ? result : null; }; function selectHomeTasks(state) { const patientWorkItems = Array.isArray(state?.patientWorkItems) ? state.patientWorkItems.filter( (item) => item !== null && typeof item === "object" && !Array.isArray(item) ) : []; const priorityOf = ({ priority }) => Number.isFinite(priority) ? priority : 0; const rankOf = ({ status }) => typeof status === "string" && Object.hasOwn(statusRank, status) ? statusRank[status] : 4; return patientWorkItems.sort((left, right) => { const statusDelta = rankOf(left) - rankOf(right); return statusDelta || priorityOf(right) - priorityOf(left); }); } function selectReports(state, filters = {}) { const family = filters?.family ?? "ALL"; const status = filters?.status ?? "ALL"; const projections = state?.reportSourceProjections; if (!projections || typeof projections !== "object" || Array.isArray(projections)) { return []; } return Object.values(projections).filter((report) => report && typeof report === "object" && !Array.isArray(report)).filter((report) => family === "ALL" || report.family === family).filter((report) => status === "ALL" || report.readStatus === status).sort((left, right) => { const issuedAtDelta = String(right.issuedAt ?? "").localeCompare(String(left.issuedAt ?? "")); return issuedAtDelta || String(left.reportId ?? "").localeCompare(String(right.reportId ?? "")); }); } var upsertProjection = (items, nextItem) => { const source = Array.isArray(items) ? items : []; const index = source.findIndex((item) => item?.id === nextItem.id); if (index < 0) { return [...source, nextItem]; } return source.map((item, itemIndex) => itemIndex === index ? { ...item, ...nextItem } : item); }; var journeyTitleByStage = { WAITING_ARRIVAL: "\u5F85\u5230\u9662", CHECKIN_AVAILABLE: "\u53EF\u4EE5\u7B7E\u5230", QUEUE_WAITING: "\u5019\u8BCA\u4E2D", VISIT_IN_PROGRESS: "\u5C31\u8BCA\u4E2D", POST_VISIT: "\u8BCA\u540E\u670D\u52A1" }; var updateJourneyProjection = (journeys, appointmentId, stage, details = {}) => upsertProjection(journeys, { id: `journey-${appointmentId}`, appointmentId, stage, title: journeyTitleByStage[stage], ...details }); var appendJourneyMessage = (messages, fixture, text) => { if (!text) { return Array.isArray(messages) ? messages : []; } return [ ...Array.isArray(messages) ? messages : [], { id: `message-${fixture.id}`, type: "JOURNEY", unread: true, title: text, createdAt: fixture.occurredAt } ]; }; var readReportInvalidationFixture = (fixture) => { const payload = isRecord(fixture?.payload) ? fixture.payload : null; const reportId = payload?.reportId; const sourceVersion = payload?.sourceVersion; const sourceHash = payload?.sourceHash; if (typeof reportId !== "string" || reportId.trim().length === 0 || !/^[A-Za-z0-9._-]+$/.test(reportId) || !Number.isInteger(sourceVersion) || sourceVersion <= 0 || typeof sourceHash !== "string" || sourceHash.trim().length === 0 || !/^[A-Za-z0-9._:-]+$/.test(sourceHash)) { return null; } return { reportId, sourceVersion, sourceHash: sourceHash.trim() }; }; var applyReportInvalidationProjection = (state, nextState, fixture) => { const { reportId, sourceVersion, sourceHash } = readReportInvalidationFixture(fixture); const report = typeof reportId === "string" && isRecord(state.reportSourceProjections) && Object.hasOwn(state.reportSourceProjections, reportId) ? state.reportSourceProjections[reportId] : null; const latestKnownVersion = Math.max( Number.isInteger(report?.sourceVersion) ? report.sourceVersion : 0, Number.isInteger(report?.invalidationVersion) ? report.invalidationVersion : 0 ); if (!isRecord(report) || report.reportId !== reportId || sourceVersion <= latestKnownVersion) { return nextState; } const withdrawn = fixture.type === "REPORT_WITHDRAWN"; const resultSnapshotProjections = Object.fromEntries( Object.entries(state.resultSnapshotProjections ?? {}).map( ([resultRef, result]) => isRecord(result) && result.reportId === reportId ? [resultRef, { ...result, valid: false, invalidatedBy: fixture.id, invalidatedReason: withdrawn ? "REPORT_WITHDRAWN" : "REPORT_CORRECTED", invalidatedSourceVersion: sourceVersion }] : [resultRef, result] ) ); const reportSourceProjections = { ...state.reportSourceProjections, [reportId]: { ...report, interpretationStatus: "INVALIDATED", invalidationVersion: sourceVersion, invalidationHash: sourceHash, invalidatedAt: fixture.occurredAt, invalidationReason: withdrawn ? "REPORT_WITHDRAWN" : "REPORT_CORRECTED" } }; const patientWorkItems = Array.isArray(state.patientWorkItems) ? state.patientWorkItems.map((item) => item?.type === "REPORT_REVIEW" && item.reportId === reportId ? { ...item, status: "ACTION_REQUIRED", stage: "REPORT_INVALIDATED", title: withdrawn ? "\u62A5\u544A\u5DF2\u64A4\u56DE" : "\u62A5\u544A\u5DF2\u66F4\u6B63", description: withdrawn ? "\u533B\u9662\u5DF2\u64A4\u56DE\u5F53\u524D\u62A5\u544A\uFF0C\u8BF7\u4EE5\u533B\u9662\u540E\u7EED\u901A\u77E5\u4E3A\u51C6" : "\u533B\u9662\u5DF2\u66F4\u65B0\u62A5\u544A\uFF0C\u539F\u8F85\u52A9\u89E3\u91CA\u5DF2\u5931\u6548", primaryAction: "VIEW_REPORT", secondaryAction: null } : item) : state.patientWorkItems; const isActiveReport = state.overlays?.reportId === reportId; return { ...nextState, reportSourceProjections, patientWorkItems, resultSnapshotProjections, overlays: isActiveReport ? { ...state.overlays, consentId: null, consentScope: null, reportView: "REPORT_UNAVAILABLE", reportUnavailableReason: "REPORT_INVALIDATED", reportFeedbackOpen: false, reportFeedbackSubmitted: false, reportServiceNotice: null } : state.overlays }; }; function applyServerProjectionFixture(state, fixture) { if (!isRecord(state) || !Array.isArray(state.appliedProjectionFixtureIds) || !isRecord(fixture) || typeof fixture.id !== "string" || fixture.id.trim().length === 0 || typeof fixture.type !== "string" || fixture.type.trim().length === 0) { return state; } if (state.appliedProjectionFixtureIds.includes(fixture.id)) { return state; } const isReportInvalidation = fixture.type === "REPORT_CORRECTED" || fixture.type === "REPORT_WITHDRAWN"; if (isReportInvalidation && !readReportInvalidationFixture(fixture)) { return state; } const issuedReport = fixture.type === "REPORT_ISSUED" ? readReportIssuedFixture(fixture) : null; if (fixture.type === "REPORT_ISSUED" && !issuedReport) { return state; } const nextState = { ...state, appliedProjectionFixtureIds: [ ...state.appliedProjectionFixtureIds, fixture.id ] }; if (fixture.type === "REPORT_ISSUED") { const report = issuedReport; const isExamination = report.family === "EXAM"; const reportId = report.reportId; const currentReport = state.reportSourceProjections?.[reportId]; const currentVersion = currentReport?.sourceVersion; const invalidationVersion = currentReport?.invalidationVersion; const conflictsWithInvalidation = Number.isInteger(invalidationVersion) && (report.sourceVersion < invalidationVersion || report.sourceVersion === invalidationVersion && report.sourceHash !== currentReport.invalidationHash); if (currentReport && (!Number.isInteger(report.sourceVersion) || !Number.isInteger(currentVersion) || report.sourceVersion <= currentVersion || conflictsWithInvalidation)) { return nextState; } const resultRef = reportResultSnapshotId(reportId); const currentResult = isRecord(state.resultSnapshotProjections) && Object.hasOwn(state.resultSnapshotProjections, resultRef) ? state.resultSnapshotProjections[resultRef] : null; const resultSnapshotProjections = currentReport && isRecord(currentResult) ? { ...state.resultSnapshotProjections, [resultRef]: { ...currentResult, valid: false, invalidatedReason: "SOURCE_UPDATED", invalidatedAt: fixture.occurredAt ?? state.demoNow } } : state.resultSnapshotProjections; const consentId = reportConsentId(reportId); const currentConsent = isRecord(state.consents) && Object.hasOwn(state.consents, consentId) ? state.consents[consentId] : null; const consents = currentReport && isRecord(currentConsent) ? { ...state.consents, [consentId]: { ...currentConsent, status: "REVOKED", revokedAt: fixture.occurredAt ?? state.demoNow } } : state.consents; const consentScopeBindings = isRecord(state.consentScopeBindings) ? Object.fromEntries( Object.entries(state.consentScopeBindings).filter( ([bindingId]) => !currentReport || bindingId !== consentId ) ) : state.consentScopeBindings; return { ...nextState, reportSourceProjections: { ...state.reportSourceProjections ?? {}, [reportId]: report }, resultSnapshotProjections, consents, consentScopeBindings, overlays: currentReport && state.overlays?.reportId === reportId ? { ...state.overlays, consentId: null, consentScope: null, reportView: "REPORT_DETAIL", reportUnavailableReason: null, reportFeedbackOpen: false, reportFeedbackSubmitted: false, reportServiceNotice: null } : state.overlays, patientWorkItems: upsertProjection( state.patientWorkItems, { id: `work-item-${reportId}`, reportId, type: "REPORT_REVIEW", status: "ACTION_REQUIRED", stage: "REPORT_AVAILABLE", priority: 90, title: `${typeof report.title === "string" && report.title.trim() ? report.title.trim() : isExamination ? "\u68C0\u67E5" : "\u68C0\u9A8C"}\u62A5\u544A\u5DF2\u51FA`, description: isExamination ? "\u533B\u9662\u68C0\u67E5\u62A5\u544A\u5DF2\u5BA1\u6838\uFF0C\u53EF\u67E5\u770B\u62A5\u544A\u8BE6\u60C5" : "18\u9879\u6307\u6807\u4E2D\u67093\u9879\u8D85\u51FA\u53C2\u8003\u8303\u56F4", primaryAction: isExamination ? "VIEW_REPORT" : "INTERPRET_REPORT", secondaryAction: isExamination ? null : "VIEW_REPORT", expiresAt: null } ), messages: upsertProjection( state.messages, { id: `message-${reportId}`, type: "REPORT", reportId, unread: true, title: `${typeof report.title === "string" && report.title.trim() ? report.title.trim() : isExamination ? "\u68C0\u67E5" : "\u68C0\u9A8C"}\u62A5\u544A\u5DF2\u51FA`, createdAt: fixture.occurredAt } ) }; } if (isReportInvalidation) { return applyReportInvalidationProjection(state, nextState, fixture); } const payload = fixture.payload ?? {}; const appointmentId = payload.appointmentId ?? "appointment-001"; let patientWorkItems = state.patientWorkItems; let journeyProjections = state.journeyProjections; let messages = state.messages; switch (fixture.type) { case "APPOINTMENT_CREATED": { patientWorkItems = upsertProjection(patientWorkItems, { id: `work-item-${appointmentId}`, appointmentId, type: "APPOINTMENT", status: "UPCOMING", stage: "WAITING_ARRIVAL", priority: 80, title: `${payload.departmentName ?? "\u95E8\u8BCA"}\u9884\u7EA6\u6210\u529F`, description: `${payload.visitTime ?? "09:30"} \xB7 ${payload.doctorName ?? "\u63A5\u8BCA\u533B\u751F"}`, primaryAction: null, secondaryAction: null, expiresAt: null }); journeyProjections = updateJourneyProjection( journeyProjections, appointmentId, "WAITING_ARRIVAL", { visitTime: payload.visitTime ?? "09:30", departmentName: payload.departmentName ?? "\u795E\u7ECF\u5185\u79D1", doctorName: payload.doctorName ?? "\u674E\u660E" } ); messages = appendJourneyMessage(messages, fixture, "\u9884\u7EA6\u6210\u529F\uFF0C\u8BF7\u6309\u65F6\u5230\u9662"); break; } case "CHECKIN_AVAILABLE": { patientWorkItems = upsertProjection(patientWorkItems, { id: `work-item-checkin-${appointmentId}`, appointmentId, type: "CHECK_IN", status: "ACTION_REQUIRED", stage: "CONFIRMATION_REQUIRED", priority: 95, title: "\u795E\u7ECF\u5185\u79D1\u53EF\u4EE5\u7B7E\u5230", description: `\u5DF2\u5230\u8FBE${payload.location ?? "\u95E8\u8BCA\u8BCA\u533A"}\uFF0C\u8BF7\u786E\u8BA4\u540E\u7B7E\u5230`, location: payload.location, primaryAction: "CONFIRM_CHECKIN", secondaryAction: "VIEW_ROUTE", expiresAt: null }); journeyProjections = updateJourneyProjection( journeyProjections, appointmentId, "CHECKIN_AVAILABLE", { location: payload.location, arrivedAt: fixture.occurredAt } ); messages = appendJourneyMessage(messages, fixture, "\u5DF2\u5230\u8FBE\u8BCA\u533A\uFF0C\u53EF\u4EE5\u7B7E\u5230"); break; } case "CHECKIN_COMPLETED": { patientWorkItems = upsertProjection(patientWorkItems, { id: `work-item-checkin-${appointmentId}`, appointmentId, type: "CHECK_IN", status: "COMPLETED", stage: "COMPLETED", priority: 95, title: "\u7B7E\u5230\u5DF2\u5B8C\u6210", description: "\u5DF2\u8FDB\u5165\u5019\u8BCA\u961F\u5217", primaryAction: null, secondaryAction: null, expiresAt: null }); patientWorkItems = upsertProjection(patientWorkItems, { id: `work-item-queue-${appointmentId}`, appointmentId, type: "WAITING_QUEUE", status: "IN_PROGRESS", stage: "QUEUE_WAITING", priority: 90, title: "\u795E\u7ECF\u5185\u79D1\u5019\u8BCA\u4E2D", description: `\u6392\u961F\u53F7 ${payload.queueNumber ?? "\u5F85\u66F4\u65B0"}`, queueNumber: payload.queueNumber, room: payload.room, primaryAction: "VIEW_QUEUE", secondaryAction: "VIEW_ROUTE", expiresAt: null }); journeyProjections = updateJourneyProjection( journeyProjections, appointmentId, "QUEUE_WAITING", { checkedInAt: fixture.occurredAt, queueNumber: payload.queueNumber, room: payload.room } ); messages = appendJourneyMessage(messages, fixture, "\u7B7E\u5230\u6210\u529F\uFF0C\u5DF2\u8FDB\u5165\u5019\u8BCA\u961F\u5217"); break; } case "QUEUE_UPDATED": { const currentQueue = patientWorkItems.find( (item) => item?.id === `work-item-queue-${appointmentId}` ); patientWorkItems = upsertProjection(patientWorkItems, { ...currentQueue ?? {}, id: `work-item-queue-${appointmentId}`, appointmentId, type: "WAITING_QUEUE", status: "IN_PROGRESS", stage: "QUEUE_WAITING", priority: 90, title: "\u795E\u7ECF\u5185\u79D1\u5019\u8BCA\u4E2D", description: `\u524D\u65B9 ${payload.peopleAhead ?? 0} \u4EBA\uFF0C\u9884\u8BA1 ${payload.estimatedMinutes ?? 0} \u5206\u949F`, queueNumber: payload.queueNumber ?? currentQueue?.queueNumber, peopleAhead: payload.peopleAhead, estimatedMinutes: payload.estimatedMinutes, room: payload.room ?? currentQueue?.room, delayed: Boolean(payload.delayed), updatedAt: fixture.occurredAt, primaryAction: "VIEW_QUEUE", secondaryAction: "VIEW_ROUTE", expiresAt: null }); journeyProjections = updateJourneyProjection( journeyProjections, appointmentId, "QUEUE_WAITING", { queueNumber: payload.queueNumber, peopleAhead: payload.peopleAhead, estimatedMinutes: payload.estimatedMinutes, room: payload.room, delayed: Boolean(payload.delayed), updatedAt: fixture.occurredAt } ); messages = appendJourneyMessage(messages, fixture, "\u5019\u8BCA\u961F\u5217\u5DF2\u66F4\u65B0"); break; } case "VISIT_STARTED": { patientWorkItems = upsertProjection(patientWorkItems, { id: `work-item-queue-${appointmentId}`, appointmentId, type: "WAITING_QUEUE", status: "COMPLETED", stage: "COMPLETED", priority: 90, title: "\u5019\u8BCA\u5DF2\u7ED3\u675F", description: "\u533B\u751F\u5DF2\u5F00\u59CB\u63A5\u8BCA", primaryAction: null, secondaryAction: null, expiresAt: null }); patientWorkItems = upsertProjection(patientWorkItems, { id: `work-item-visit-${appointmentId}`, appointmentId, type: "VISIT", status: "IN_PROGRESS", stage: "VISIT_IN_PROGRESS", priority: 100, title: "\u533B\u751F\u63A5\u8BCA\u4E2D", description: payload.room ?? "\u8BF7\u5728\u8BCA\u5BA4\u5185\u5B8C\u6210\u5C31\u8BCA", primaryAction: null, secondaryAction: null, expiresAt: null }); journeyProjections = updateJourneyProjection( journeyProjections, appointmentId, "VISIT_IN_PROGRESS", { room: payload.room, startedAt: fixture.occurredAt } ); messages = appendJourneyMessage(messages, fixture, "\u533B\u751F\u5DF2\u5F00\u59CB\u63A5\u8BCA"); break; } case "VISIT_COMPLETED": { patientWorkItems = upsertProjection(patientWorkItems, { id: `work-item-visit-${appointmentId}`, appointmentId, type: "VISIT", status: "COMPLETED", stage: "COMPLETED", priority: 100, title: "\u672C\u6B21\u5C31\u8BCA\u5DF2\u5B8C\u6210", description: "\u8BCA\u540E\u8BB0\u5F55\u4E0E\u670D\u52A1\u5DF2\u66F4\u65B0", primaryAction: null, secondaryAction: null, expiresAt: null }); patientWorkItems = upsertProjection(patientWorkItems, { id: `work-item-post-visit-${appointmentId}`, appointmentId, type: "POST_VISIT", status: "ACTION_REQUIRED", stage: "POST_VISIT", priority: 70, title: "\u67E5\u770B\u8BCA\u540E\u670D\u52A1", description: "\u67E5\u770B\u95E8\u8BCA\u8BB0\u5F55\u3001\u5904\u65B9\u548C\u590D\u8BCA\u5EFA\u8BAE", primaryAction: null, secondaryAction: null, expiresAt: null }); journeyProjections = updateJourneyProjection( journeyProjections, appointmentId, "POST_VISIT", { completedAt: fixture.occurredAt } ); messages = appendJourneyMessage(messages, fixture, "\u5C31\u8BCA\u5B8C\u6210\uFF0C\u8BCA\u540E\u670D\u52A1\u5DF2\u66F4\u65B0"); break; } default: return nextState; } return { ...nextState, patientWorkItems, journeyProjections, messages, activeAgentTaskProjection: state.activeAgentTaskProjection, commandProjections: state.commandProjections }; } function requestReportInterpretation(state, reportId) { if (!Array.isArray(state?.patientWorkItems)) { return state; } const itemIndex = state.patientWorkItems.findIndex( (item) => item?.type === "REPORT_REVIEW" && item.reportId === reportId ) ?? -1; if (itemIndex < 0) { return state; } const hasConsent = hasValidReportConsent(state, reportId); const gate = evaluateReportInterpretationGate(state, reportId); const consentId = reportConsentId(reportId); if (!gate.allowed) { const unavailableReason = [ "OCR_REVIEW_REQUIRED", "CRITICAL_NOTICE", "AI_UNAVAILABLE", "UNSUPPORTED" ].includes(gate.reason) ? gate.reason : "UNSUPPORTED"; const currentInterpretationStatus = state.reportSourceProjections?.[reportId]?.interpretationStatus; return { ...state, patientWorkItems: state.patientWorkItems.map((item, index) => index === itemIndex ? { ...item, stage: "REPORT_UNAVAILABLE" } : item), reportSourceProjections: { ...state.reportSourceProjections, [reportId]: { ...state.reportSourceProjections[reportId], interpretationStatus: currentInterpretationStatus === "INVALIDATED" ? "INVALIDATED" : "NOT_REQUESTED" } }, overlays: { ...state.overlays, consentId: null, consentScope: null, reportId, reportView: "REPORT_UNAVAILABLE", reportUnavailableReason: unavailableReason } }; } const existingResult = selectValidReportResult(state, reportId); if (hasConsent && gate.allowed && state.reportSourceProjections?.[reportId]?.interpretationStatus === "READY" && existingResult) { return { ...state, patientWorkItems: state.patientWorkItems.map((item, index) => index === itemIndex ? { ...item, stage: "INTERPRETED" } : item), overlays: { ...state.overlays, consentId: null, consentScope: null, reportId, reportView: "INTERPRETED" } }; } const patientWorkItems = state.patientWorkItems.map((item, index) => index === itemIndex ? { ...item, stage: hasConsent ? "INTERPRETING" : "CONSENT_REQUIRED" } : item); return { ...state, patientWorkItems, reportSourceProjections: hasConsent ? { ...state.reportSourceProjections, [reportId]: { ...state.reportSourceProjections[reportId], interpretationStatus: "GENERATING" } } : state.reportSourceProjections, overlays: { ...state.overlays, consentId: hasConsent ? null : consentId, consentScope: hasConsent ? null : { patientId: state.activePatientId, reportId }, reportId, reportView: hasConsent ? "INTERPRETING" : state?.overlays?.reportView ?? null } }; } function evaluateReportInterpretationGate(state, reportId) { const report = state?.reportSourceProjections?.[reportId]; if (!report || typeof report !== "object" || Array.isArray(report)) { return { allowed: false, reason: "REPORT_NOT_FOUND" }; } if (report.family !== "LAB" || report.reportType !== "BLOOD_ROUTINE") { return { allowed: false, reason: "UNSUPPORTED" }; } if (report.sourceStatus !== "FINAL") { return { allowed: false, reason: "SOURCE_NOT_FINAL" }; } if (report.verificationStatus !== "VERIFIED") { return { allowed: false, reason: typeof report.verificationReason === "string" ? report.verificationReason : "VERIFICATION_REQUIRED" }; } if (report.criticalNotice === true) { return { allowed: false, reason: "CRITICAL_NOTICE" }; } if (report.interpretationStatus === "INVALIDATED") { return { allowed: false, reason: "REPORT_INVALIDATED" }; } if (report.interpretationUnavailableReason === "AI_UNAVAILABLE" || report.interpretationUnavailableReason === "UNSUPPORTED") { return { allowed: false, reason: report.interpretationUnavailableReason }; } return { allowed: true, reason: null }; } function grantConsent(state, consentId) { const reportId = state?.overlays?.reportId; const expectedConsentId = typeof reportId === "string" ? reportConsentId(reportId) : null; const scope = state?.overlays?.consentScope; if (consentId !== expectedConsentId || state?.overlays?.consentId !== consentId || scope?.patientId !== state?.activePatientId || scope?.reportId !== reportId || !Array.isArray(state?.patientWorkItems)) { return state; } const itemIndex = state?.patientWorkItems?.findIndex( (item) => item?.type === "REPORT_REVIEW" && item.reportId === reportId && item.stage === "CONSENT_REQUIRED" ) ?? -1; if (itemIndex < 0 || !evaluateReportInterpretationGate(state, reportId).allowed) { return state; } const consent = { id: consentId, purpose: "\u7528\u4E8E\u672C\u6B21\u62A5\u544A\u7684 AI \u8F85\u52A9\u89E3\u91CA", scope: "\u5F53\u524D\u8840\u5E38\u89C4\u62A5\u544A", expiresAt: "2026-07-09T23:59:59+08:00", revocable: true, status: "GRANTED" }; const binding = { patientId: state.activePatientId, reportId }; const pendingConsentState = { ...state, consents: { ...state.consents, [consentId]: consent }, consentScopeBindings: { ...state.consentScopeBindings, [consentId]: binding } }; if (!hasValidReportConsent(pendingConsentState, reportId)) { return { ...state, patientWorkItems: state.patientWorkItems.map((item, index) => index === itemIndex ? { ...item, stage: "REPORT_AVAILABLE" } : item), reportSourceProjections: { ...state.reportSourceProjections, [reportId]: { ...state.reportSourceProjections[reportId], interpretationStatus: "NOT_REQUESTED" } }, overlays: { ...state.overlays, consentId: null, consentScope: null, reportView: "REPORT_DETAIL" } }; } return { ...state, consents: pendingConsentState.consents, consentScopeBindings: pendingConsentState.consentScopeBindings, reportSourceProjections: { ...state.reportSourceProjections, [reportId]: { ...state.reportSourceProjections[reportId], interpretationStatus: "GENERATING" } }, patientWorkItems: state.patientWorkItems.map((item, index) => { if (index === itemIndex) { return { ...item, stage: "INTERPRETING" }; } return item; }), resultSnapshotProjections: { ...state.resultSnapshotProjections ?? {} }, overlays: { ...state.overlays, consentId: null, consentScope: null, reportView: "INTERPRETING" } }; } function openReportDetails(state, reportId) { const exists = state?.patientWorkItems?.some( (item) => item?.type === "REPORT_REVIEW" && item.reportId === reportId ); const report = state?.reportSourceProjections?.[reportId]; const hasConsistentSource = report && typeof report === "object" && !Array.isArray(report) && (report.reportId === void 0 || report.reportId === reportId); if (!exists || !hasConsistentSource) { return state; } const isExamination = report.family === "EXAM"; const gate = isExamination ? { allowed: true, reason: null } : evaluateReportInterpretationGate(state, reportId); const unavailableReason = gate.allowed ? null : [ "OCR_REVIEW_REQUIRED", "CRITICAL_NOTICE", "AI_UNAVAILABLE", "UNSUPPORTED" ].includes(gate.reason) ? gate.reason : "UNSUPPORTED"; return { ...state, reportSourceProjections: { ...state.reportSourceProjections ?? {}, [reportId]: { ...report, readStatus: "READ" } }, overlays: { ...state.overlays, reportId, reportView: unavailableReason ? "REPORT_UNAVAILABLE" : "REPORT_DETAIL", reportUnavailableReason: unavailableReason, reportExpanded: false, reportFeedbackOpen: false, reportFeedbackSubmitted: false, reportServiceNotice: null } }; } function closeReportView(state) { if (!state?.overlays?.reportId && !state?.overlays?.reportView) { return state; } return { ...state, overlays: { ...state.overlays, consentId: null, consentScope: null, reportId: null, reportView: null, reportUnavailableReason: null, reportExpanded: false, reportFeedbackOpen: false, reportFeedbackSubmitted: false, reportServiceNotice: null } }; } function rejectConsent(state, consentId) { const reportId = state?.overlays?.reportId; if (consentId !== reportConsentId(reportId) || state?.overlays?.consentId !== consentId || state?.overlays?.consentScope?.patientId !== state?.activePatientId || state?.overlays?.consentScope?.reportId !== reportId || !Array.isArray(state?.patientWorkItems)) { return state; } const hasPendingItem = state.patientWorkItems?.some( (item) => item?.type === "REPORT_REVIEW" && item.reportId === reportId && item.stage === "CONSENT_REQUIRED" ); if (typeof reportId !== "string" || !hasPendingItem) { return state; } return { ...state, patientWorkItems: state.patientWorkItems.map((item) => item?.type === "REPORT_REVIEW" && item.reportId === reportId ? { ...item, stage: "REPORT_AVAILABLE" } : item), overlays: { ...state.overlays, consentId: null, consentScope: null, reportView: "REPORT_DETAIL" } }; } function applyReportInterpretationProjectionFixture(state, reportId) { const itemIndex = state?.patientWorkItems?.findIndex( (item) => item?.type === "REPORT_REVIEW" && item.reportId === reportId && item.stage === "INTERPRETING" ) ?? -1; const consentGranted = hasValidReportConsent(state, reportId); const gate = evaluateReportInterpretationGate(state, reportId); const source = state?.reportSourceProjections?.[reportId]; if (itemIndex < 0 || !consentGranted || !gate.allowed || !isRecord(source)) { return state; } const result = { ...reportInterpretationProjectionFixture, resultRef: reportResultSnapshotId(reportId), reportId, sourceVersion: source.sourceVersion, sourceHash: source.sourceHash, valid: true, interpretation: { ...reportInterpretationProjectionFixture.interpretation, highlights: reportInterpretationProjectionFixture.interpretation.highlights.map((highlight) => ({ ...highlight })), explanations: reportInterpretationProjectionFixture.interpretation.explanations.map((explanation) => ({ ...explanation })), canDo: [ ...reportInterpretationProjectionFixture.interpretation.canDo ], evidence: [ ...reportInterpretationProjectionFixture.interpretation.evidence ] } }; return { ...state, patientWorkItems: state.patientWorkItems.map((item, index) => index === itemIndex ? { ...item, stage: "INTERPRETED" } : item), reportSourceProjections: { ...state.reportSourceProjections, [reportId]: { ...state.reportSourceProjections[reportId], interpretationStatus: "READY" } }, resultSnapshotProjections: { ...state.resultSnapshotProjections, [result.resultRef]: result }, overlays: { ...state.overlays, consentId: null, reportId, reportView: "INTERPRETED" } }; } function submitReportFeedback(state, payload = {}) { const reportId = payload?.reportId; const category = payload?.category; const reportSources = state?.reportSourceProjections; const report = typeof reportId === "string" && reportId.length > 0 && reportSources && typeof reportSources === "object" && !Array.isArray(reportSources) && Object.hasOwn(reportSources, reportId) ? reportSources[reportId] : null; const hasReportTask = Array.isArray(state?.patientWorkItems) && state.patientWorkItems.some((item) => item?.type === "REPORT_REVIEW" && item.reportId === reportId); const result = selectValidReportResult(state, reportId); if (!report || typeof report !== "object" || Array.isArray(report) || report.reportId !== reportId || !hasReportTask || !reportFeedbackCategories.has(category) || !Array.isArray(state?.reportFeedback) || !hasValidReportConsent(state, reportId) || !evaluateReportInterpretationGate(state, reportId).allowed || report.interpretationStatus !== "READY" || !result) { return state; } const feedback = { id: [ "feedback", encodeReportId(reportId), report.sourceVersion, category ].join("-"), reportId, sourceVersion: report.sourceVersion, sourceHash: report.sourceHash, resultRef: result.resultRef, resultVersion: result.resultVersion, category }; if (state.reportFeedback.some((item) => item?.id === feedback.id)) { return state; } return { ...state, reportFeedback: [...state.reportFeedback, feedback] }; } function revokeConsent(state, consentId) { if (!isRecord(state) || typeof consentId !== "string" || !isRecord(state.consents) || !isRecord(state.consentScopeBindings) || !isRecord(state.reportSourceProjections) || !isRecord(state.resultSnapshotProjections) || !isRecord(state.overlays) || !Array.isArray(state.patientWorkItems) || !Object.hasOwn(state.consents, consentId) || !Object.hasOwn(state.consentScopeBindings, consentId)) { return state; } const consent = state.consents[consentId]; const binding = state.consentScopeBindings[consentId]; if (!isRecord(consent) || !isRecord(binding) || typeof binding.reportId !== "string" || !Object.hasOwn(state.reportSourceProjections, binding.reportId) || !isRecord(state.reportSourceProjections[binding.reportId]) || consentId !== reportConsentId(binding.reportId) || consent?.id !== consentId || binding?.patientId !== state?.activePatientId) { return state; } const reportId = binding.reportId; const consentScopeBindings = Object.fromEntries( Object.entries(state.consentScopeBindings).filter( ([bindingConsentId]) => bindingConsentId !== consentId ) ); const resultSnapshotProjections = Object.fromEntries( Object.entries(state.resultSnapshotProjections ?? {}).filter( ([, result]) => result?.reportId !== reportId ) ); return { ...state, consents: { ...state.consents, [consentId]: { ...consent, status: "REVOKED" } }, consentScopeBindings, reportSourceProjections: { ...state.reportSourceProjections, [reportId]: { ...state.reportSourceProjections[reportId], interpretationStatus: "NOT_REQUESTED" } }, patientWorkItems: state.patientWorkItems.map((item) => item?.type === "REPORT_REVIEW" && item.reportId === reportId ? { ...item, stage: "REPORT_AVAILABLE" } : item), resultSnapshotProjections, overlays: { ...state.overlays, consentId: null, consentScope: null, reportId, reportView: "REPORT_DETAIL", reportFeedbackOpen: false, reportFeedbackSubmitted: false, reportServiceNotice: null } }; } var scenarioNames = /* @__PURE__ */ new Set([ "REPORT_ARRIVED", "REPORT_DETAIL", "REPORT_CONSENT", "REPORT_GENERATING", "REPORT_READY", "REPORT_NEED_REVIEW", "REPORT_CRITICAL", "REPORT_INVALIDATED", "EMPTY_HOME", "REGISTRATION_QUERY", "COMMAND_PREPARED", "APPOINTMENT_CREATED", "CHECKIN_AVAILABLE", "QUEUE_UPDATED" ]); var loadRegistrationScenario = (base) => submitInteraction( base, registrationDemoText ); var loadLockedRegistrationScenario = (base) => { const queried = loadRegistrationScenario(base); return applyCandidateSelectionResponseFixture(queried, { id: "scenario-selection-success-001", outcome: "SUCCESS", resultRef: "result-slot-001", resultVersion: 1, candidateId: "candidate-slot-0930", validation: { tenantMatched: true, patientMatched: true, sessionMatched: true, versionMatched: true, notExpired: true, realtimeAvailable: true, l1LockSucceeded: true }, lock: { lockId: "lock-slot-001", expiresAt: "2026-07-03T09:05:00+08:00" } }); }; var loadCommandPreparedScenario = (base) => { const locked = loadLockedRegistrationScenario(base); return applyCommandProjectionFixture(locked, { id: "scenario-command-awaiting-001", commandId: "command-register-001", version: 1, riskLevel: "L2", status: "AWAITING_CONFIRMATION", details: { operationName: "\u786E\u8BA4\u6302\u53F7", patientName: "\u5F20\u5148\u751F", departmentName: "\u795E\u7ECF\u5185\u79D1", doctorName: "\u674E\u660E", doctorTitle: "\u4E3B\u4EFB\u533B\u5E08", visitAt: "2026-07-03 09:30", fee: "30\u5143", expiresAt: "2026-07-03T09:05:00+08:00", countdown: "\u5269\u4F59 5 \u5206\u949F", candidateId: "candidate-slot-0930" } }); }; function loadScenario(state, scenarioName) { const normalized = scenarioNames.has(scenarioName) ? scenarioName : "EMPTY_HOME"; const base = { ...createInitialState({ activePatientId: state?.activePatientId ?? "patient-zhang-san" }), demoScenario: normalized }; const reportFixture = { id: "scenario-report-arrived-001", type: "REPORT_ISSUED", occurredAt: "2026-07-03T09:30:00+08:00", payload: { reportId: "report-blood-20260702" } }; switch (normalized) { case "REPORT_ARRIVED": return { ...applyServerProjectionFixture(base, reportFixture), demoScenario: normalized }; case "REPORT_DETAIL": { const report = applyServerProjectionFixture(base, reportFixture); return { ...openReportDetails(report, "report-blood-20260702"), demoScenario: normalized }; } case "REPORT_CONSENT": { const report = openReportDetails( applyServerProjectionFixture(base, reportFixture), "report-blood-20260702" ); return { ...requestReportInterpretation(report, "report-blood-20260702"), demoScenario: normalized }; } case "REPORT_GENERATING": { const pending = loadScenario(base, "REPORT_CONSENT"); return { ...grantConsent( pending, "consent-ai-report-blood-20260702" ), demoScenario: normalized }; } case "REPORT_NEED_REVIEW": { const report = applyServerProjectionFixture(base, { ...reportFixture, payload: { ...reportFixture.payload, verificationStatus: "NEED_REVIEW", verificationReason: "OCR_REVIEW_REQUIRED" } }); return { ...openReportDetails(report, "report-blood-20260702"), demoScenario: normalized }; } case "REPORT_CRITICAL": { const report = applyServerProjectionFixture(base, { ...reportFixture, payload: { ...reportFixture.payload, criticalNotice: true } }); return { ...openReportDetails(report, "report-blood-20260702"), demoScenario: normalized }; } case "REPORT_INVALIDATED": { const ready = loadScenario(base, "REPORT_READY"); return { ...applyServerProjectionFixture(ready, { id: "scenario-report-corrected-002", type: "REPORT_CORRECTED", occurredAt: "2026-07-03T11:00:00+08:00", payload: { reportId: "report-blood-20260702", sourceVersion: 2, sourceHash: "sha256:blood-v2" } }), demoScenario: normalized }; } case "REPORT_READY": { const report = applyServerProjectionFixture(base, reportFixture); const pending = requestReportInterpretation( report, "report-blood-20260702" ); const interpreting = grantConsent( pending, "consent-ai-report-blood-20260702" ); return { ...applyReportInterpretationProjectionFixture( interpreting, "report-blood-20260702" ), demoScenario: normalized }; } case "REGISTRATION_QUERY": return { ...loadRegistrationScenario(base), demoScenario: normalized }; case "COMMAND_PREPARED": return { ...loadCommandPreparedScenario(base), demoScenario: normalized }; case "APPOINTMENT_CREATED": { const awaiting = loadCommandPreparedScenario(base); return { ...applyCommandProjectionFixture(awaiting, { id: "scenario-command-succeeded-001", commandId: "command-register-001", status: "SUCCEEDED", resultFixtureId: "appointment-created-001" }), activeTab: "home", demoScenario: normalized }; } case "CHECKIN_AVAILABLE": { const appointment = loadScenario(base, "APPOINTMENT_CREATED"); return { ...applyServerProjectionFixture(appointment, { id: "scenario-checkin-available-001", type: "CHECKIN_AVAILABLE", occurredAt: "2026-07-03T09:10:00+08:00", payload: { appointmentId: "appointment-001", location: "\u95E8\u8BCA\u4E09\u697C\u795E\u7ECF\u5185\u79D1\u8BCA\u533A" } }), demoScenario: normalized }; } case "QUEUE_UPDATED": { const arrived = loadScenario(base, "CHECKIN_AVAILABLE"); const checkedIn = applyServerProjectionFixture(arrived, { id: "scenario-checkin-completed-001", type: "CHECKIN_COMPLETED", occurredAt: "2026-07-03T09:12:00+08:00", payload: { appointmentId: "appointment-001", queueNumber: "A023", room: "3F-08\u8BCA\u5BA4" } }); return { ...applyServerProjectionFixture(checkedIn, { id: "scenario-queue-updated-001", type: "QUEUE_UPDATED", occurredAt: "2026-07-03T09:18:00+08:00", payload: { appointmentId: "appointment-001", queueNumber: "A023", peopleAhead: 4, estimatedMinutes: 18, room: "3F-08\u8BCA\u5BA4", delayed: true } }), demoScenario: normalized }; } default: return base; } } // docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.js var navItems = Object.freeze([ { id: "home", label: "\u9996\u9875", icon: "house" }, { id: "care", label: "\u5C31\u533B", icon: "stethoscope" }, { id: "assistant", label: "AI\u52A9\u624B", icon: "sparkles" }, { id: "records", label: "\u5065\u5EB7\u6863\u6848", icon: "folder-heart" }, { id: "profile", label: "\u6211\u7684", icon: "user-round" } ]); var demoScenarioGroups = Object.freeze({ REPORT_CLOSURE: Object.freeze([ "REPORT_ARRIVED", "REPORT_DETAIL", "REPORT_CONSENT", "REPORT_GENERATING", "REPORT_READY", "REPORT_NEED_REVIEW", "REPORT_CRITICAL", "REPORT_INVALIDATED" ]), CARE_CLOSURE: Object.freeze([ "EMPTY_HOME", "REGISTRATION_QUERY", "COMMAND_PREPARED", "APPOINTMENT_CREATED", "CHECKIN_AVAILABLE", "QUEUE_UPDATED" ]) }); var demoScenarios = Object.freeze( Object.values(demoScenarioGroups).flat() ); var scenarioLabels = { EMPTY_HOME: "\u7A7A\u95F2\u9996\u9875", REPORT_ARRIVED: "\u62A5\u544A\u5230\u8FBE", REPORT_DETAIL: "\u62A5\u544A\u8BE6\u60C5", REPORT_CONSENT: "\u62A5\u544A\u6388\u6743", REPORT_GENERATING: "\u89E3\u8BFB\u751F\u6210\u4E2D", REPORT_READY: "\u62A5\u544A\u5DF2\u89E3\u8BFB", REPORT_NEED_REVIEW: "\u62A5\u544A\u9700\u590D\u6838", REPORT_CRITICAL: "\u62A5\u544A\u5371\u6025\u503C", REPORT_INVALIDATED: "\u62A5\u544A\u5DF2\u5931\u6548", REGISTRATION_QUERY: "\u81EA\u7136\u8BED\u8A00\u67E5\u53F7", COMMAND_PREPARED: "\u6302\u53F7\u5F85\u786E\u8BA4", APPOINTMENT_CREATED: "\u6302\u53F7\u6210\u529F", CHECKIN_AVAILABLE: "\u5230\u9662\u53EF\u7B7E\u5230", QUEUE_UPDATED: "\u5019\u8BCA\u66F4\u65B0" }; var homeServices = Object.freeze([ { label: "\u9884\u7EA6\u6302\u53F7", icon: "calendar-plus" }, { label: "\u667A\u80FD\u5BFC\u8BCA", icon: "scan-heart" }, { label: "\u62A5\u544A\u67E5\u8BE2", icon: "file-chart-column" }, { label: "\u95E8\u8BCA\u7F34\u8D39", icon: "wallet-cards" }, { label: "\u68C0\u67E5\u9884\u7EA6", icon: "clipboard-clock" }, { label: "\u4F4F\u9662\u670D\u52A1", icon: "bed" }, { label: "\u9662\u5185\u5BFC\u822A", icon: "map-pinned" }, { label: "\u5728\u7EBF\u95EE\u8BCA", icon: "messages-square" } ]); var actionLabels = { INTERPRET_REPORT: "AI \u89E3\u8BFB\u62A5\u544A", VIEW_REPORT: "\u67E5\u770B\u539F\u62A5\u544A", CONFIRM_CHECKIN: "\u786E\u8BA4\u7B7E\u5230", VIEW_ROUTE: "\u67E5\u770B\u8DEF\u7EBF", VIEW_QUEUE: "\u67E5\u770B\u5019\u8BCA" }; var actionTokens = { INTERPRET_REPORT: "interpret-report", VIEW_REPORT: "view-report", CONFIRM_CHECKIN: "open-checkin-confirmation", VIEW_ROUTE: "open-route", VIEW_QUEUE: "open-queue" }; var statusPresentation = { ACTION_REQUIRED: { className: "action-required", icon: "circle-alert", label: "\u9700\u8981\u5904\u7406" }, IN_PROGRESS: { className: "in-progress", icon: "loader-circle", label: "\u8FDB\u884C\u4E2D" }, UPCOMING: { className: "upcoming", icon: "calendar-clock", label: "\u5373\u5C06\u5F00\u59CB" }, COMPLETED: { className: "completed", icon: "circle-check-big", label: "\u5DF2\u5B8C\u6210" } }; var unknownStatusPresentation = { className: "unknown", icon: "circle-help", label: "\u72B6\u6001\u5F85\u786E\u8BA4" }; var escapeHtml = (value) => String(value ?? "").replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'"); var getActionLabel = (action) => typeof action === "string" && Object.hasOwn(actionLabels, action) ? actionLabels[action] : null; var renderActionAttributes = (action, task) => { const token = typeof action === "string" && Object.hasOwn(actionTokens, action) ? actionTokens[action] : null; if (!token) { return ""; } if (typeof task?.reportId === "string") { return ` data-action="${token}" data-report-id="${escapeHtml(task.reportId)}"`; } if (typeof task?.appointmentId === "string") { return ` data-action="${token}" data-appointment-id="${escapeHtml(task.appointmentId)}"`; } return ""; }; var getStatusPresentation = (status) => typeof status === "string" && Object.hasOwn(statusPresentation, status) ? statusPresentation[status] : unknownStatusPresentation; var getShellElements = (root) => { if (!root?.getElementById) { return null; } const appHeader = root.getElementById("appHeader"); const appView = root.getElementById("appView"); const bottomNav = root.getElementById("bottomNav"); return appHeader && appView && bottomNav ? { appHeader, appView, bottomNav } : null; }; var renderIcons = () => { const lucide = globalThis.lucide; if (lucide?.createIcons) { lucide.createIcons({ attrs: { "aria-hidden": "true" } }); } }; var patientDisplayNames = { "patient-zhang-san": "\u5F20\u5148\u751F", "patient-li-na": "\u674E\u5973\u58EB" }; var patientDisplayName = (state) => patientDisplayNames[state?.activePatientId] ?? "\u5F53\u524D\u5C31\u8BCA\u4EBA"; var renderHeader = (state) => { const messages = Array.isArray(state?.messages) ? state.messages : []; const unreadCount = messages.filter((message) => message?.unread).length; const messageLabel = unreadCount > 0 ? `\u6D88\u606F\uFF0C${unreadCount} \u6761\u672A\u8BFB` : "\u6D88\u606F"; return `

\u7A7A\u6D77\u533B\u9662

\u5F53\u524D\u9662\u533A \xB7 \u7A7A\u6D77\u533B\u9662\u672C\u9662

`; }; var journeyStages = [ { stage: "WAITING_ARRIVAL", label: "\u5230\u9662", time: "09:10" }, { stage: "CHECKIN_AVAILABLE", label: "\u7B7E\u5230", time: "09:20" }, { stage: "QUEUE_WAITING", label: "\u5019\u8BCA", time: "09:30" }, { stage: "VISIT_IN_PROGRESS", label: "\u533B\u751F\u63A5\u8BCA", time: "10:05" }, { stage: "POST_VISIT", label: "\u8BCA\u540E\u670D\u52A1", time: "10:25" } ]; var renderJourneyProjection = (journey) => { const activeIndex = Math.max( 0, journeyStages.findIndex(({ stage }) => stage === journey.stage) ); const start = Math.max( 0, Math.min(activeIndex - 1, journeyStages.length - 3) ); const visibleStages = journeyStages.slice(start, start + 3); return `
${escapeHtml(journey.title)}

${escapeHtml(journey.location ?? journey.room ?? "\u9662\u5185\u884C\u7A0B\u6301\u7EED\u66F4\u65B0")}

${journey.stage === "QUEUE_WAITING" ? ` ` : ""}
    ${visibleStages.map((node) => `
  1. ${node.label}
  2. `).join("")}
`; }; var renderHome = (state) => { const tasks = selectHomeTasks(state); const journeys = Array.isArray(state?.journeyProjections) ? state.journeyProjections : []; const primaryTaskIndex = tasks.findIndex( ({ primaryAction, status }) => (status === "ACTION_REQUIRED" || status === "IN_PROGRESS") && Boolean(getActionLabel(primaryAction)) ); const activeTaskCount = tasks.filter( ({ status }) => status === "ACTION_REQUIRED" || status === "IN_PROGRESS" ).length; return `

AI \u5C31\u533B\u52A9\u624B

${patientDisplayName(state)}\uFF0C\u4E0A\u5348\u597D

${activeTaskCount > 0 ? `\u6709 ${activeTaskCount} \u9879\u5C31\u533B\u4E8B\u9879\u9700\u8981\u5173\u6CE8` : "\u4ECA\u5929\u6682\u65E0\u5F85\u5904\u7406\u7684\u5C31\u533B\u4E8B\u9879"}

\u7A7A\u6D77\u533B\u9662 AI \u533B\u751F\u52A9\u624B

\u5C31\u533B\u4EFB\u52A1

\u73B0\u5728\u8981\u505A

${tasks.length === 0 ? `
\u4ECA\u5929\u6CA1\u6709\u5F85\u5904\u7406\u4E8B\u9879

\u65B0\u7684\u62A5\u544A\u3001\u7F34\u8D39\u6216\u9884\u7EA6\u63D0\u9192\u4F1A\u663E\u793A\u5728\u8FD9\u91CC\u3002

` : tasks.map((task, index) => { const isCompleted = task.status === "COMPLETED"; const status = getStatusPresentation(task.status); const isPrimaryTask = index === primaryTaskIndex; const primaryActionLabel = getActionLabel(task.primaryAction); const secondaryActionLabel = getActionLabel(task.secondaryAction); const canAct = (task.status === "ACTION_REQUIRED" || task.status === "IN_PROGRESS") && Boolean(primaryActionLabel); const recommendation = isCompleted ? "\u65E0\u9700\u64CD\u4F5C" : canAct ? primaryActionLabel : task.status === "UPCOMING" ? "\u7B49\u5F85\u4E8B\u9879\u5F00\u59CB" : "\u786E\u8BA4\u72B6\u6001\u4E0E\u53EF\u7528\u64CD\u4F5C"; return `
${status.label}

${escapeHtml(task.title)}

\u53D1\u751F\u4E86\u4EC0\u4E48\uFF1A${escapeHtml(task.description)}

\u4E3A\u4EC0\u4E48\u5173\u6CE8\uFF1A${isCompleted ? "\u8BE5\u4E8B\u9879\u5DF2\u5904\u7406\u5B8C\u6210\u3002" : "\u53CA\u65F6\u5904\u7406\u6709\u52A9\u4E8E\u987A\u5229\u63A8\u8FDB\u540E\u7EED\u5C31\u533B\u5B89\u6392\u3002"}

\u5EFA\u8BAE\u64CD\u4F5C ${recommendation}
${canAct ? `
${secondaryActionLabel ? ` ` : ""}
` : ""}
`; }).join("")}

\u9662\u5185\u8FDB\u5EA6

\u4ECA\u65E5\u65C5\u7A0B

${journeys.length > 0 ? journeys.map(renderJourneyProjection).join("") : `
\u4ECA\u5929\u6682\u65E0\u9662\u5185\u884C\u7A0B

\u6302\u53F7\u6216\u68C0\u67E5\u5B89\u6392\u786E\u8BA4\u540E\uFF0C\u5C06\u5C55\u793A\u524D\u540E\u6B65\u9AA4\u548C\u5F53\u524D\u8282\u70B9\u3002

`}

\u5FEB\u6377\u5165\u53E3

\u5E38\u7528\u670D\u52A1

${homeServices.map(({ label, icon }) => ` `).join("")}

\u5065\u5EB7\u63D0\u9192

\u4E3B\u52A8\u5173\u6000

\u6682\u65E0\u65B0\u7684\u4E3B\u52A8\u5173\u6000\u63D0\u9192

\u7528\u836F\u3001\u590D\u8BCA\u4E0E\u68C0\u67E5\u51C6\u5907\u63D0\u9192\u4F1A\u5728\u786E\u8BA4\u540E\u5C55\u793A\u3002

`; }; var candidateToken = /^[a-z0-9]+(?:-[a-z0-9]+)*$/; var renderAssistantMessages = (messages) => Array.isArray(messages) ? messages.filter((message) => message && typeof message === "object" && (message.role === "user" || message.role === "assistant")).map(({ role, text }) => `
${role === "user" ? "\u4F60" : "AI \u52A9\u624B"}

${escapeHtml(text)}

`).join("") : ""; var renderAssistant = (state) => { const task = state?.activeAgentTaskProjection; const result = typeof task?.activeResultRef === "string" ? state?.resultSnapshotProjections?.[task.activeResultRef] : null; const items = task?.stage === "CANDIDATE_SELECTION" && result?.resultRef === task.activeResultRef && Array.isArray(result?.items) ? result.items : []; const candidates = items.filter((item) => item && typeof item === "object" && typeof item.candidateId === "string" && candidateToken.test(item.candidateId)); const hasTask = task?.type === "REGISTRATION"; return `

\u81EA\u7136\u8BED\u8A00\u5C31\u533B\u670D\u52A1

AI \u52A9\u624B

${hasTask ? ` ` : ""}

\u573A\u666F\u5EFA\u8BAE

${renderAssistantMessages(state?.messages)} ${task?.stage === "REQUERY_REQUIRED" ? ` ` : ""} ${result ? `

\u53EF\u9009\u53F7\u6E90

${escapeHtml(result.text)}

${candidates.length > 0 ? `
${candidates.map((item) => ` `).join("")}
` : ""}
` : ""} ${task?.stage === "AWAITING_REGISTRATION_CONFIRMATION" ? ` ` : ""}
`; }; var reportFamilyLabels = { LAB: "\u68C0\u9A8C\u62A5\u544A", EXAM: "\u68C0\u67E5\u62A5\u544A" }; var reportSourceStatusLabels = { FINAL: "\u5DF2\u5BA1\u6838", PRELIMINARY: "\u5F85\u5BA1\u6838" }; var reportInterpretationLabels = { NOT_REQUESTED: "\u5C1A\u672A\u8FDB\u884C AI \u8F85\u52A9\u89E3\u8BFB", INTERPRETING: "AI \u8F85\u52A9\u89E3\u8BFB\u4E2D", READY: "AI \u8F85\u52A9\u89E3\u8BFB\u5DF2\u751F\u6210", NEED_REVIEW: "\u89E3\u8BFB\u7ED3\u679C\u5EFA\u8BAE\u7531\u533B\u751F\u786E\u8BA4" }; var metricFlagLabels = { HIGH: "\u504F\u9AD8", LOW: "\u504F\u4F4E", NORMAL: "\u6B63\u5E38" }; var abnormalMetricsOf = (report) => Array.isArray(report?.metrics) ? report.metrics.filter((metric) => ["HIGH", "LOW"].includes(metric?.sourceFlag)) : []; var renderMetric = (metric) => { const name = escapeHtml(metric?.name || "\u672A\u547D\u540D\u6307\u6807"); const value = metric?.value === null || metric?.value === void 0 ? "\u2014" : escapeHtml(metric.value); const unit = metric?.unit ? ` ${escapeHtml(metric.unit)}` : ""; const range = metric?.referenceRange ? `\u53C2\u8003\u8303\u56F4 ${escapeHtml(metric.referenceRange)}${unit}` : "\u53C2\u8003\u8303\u56F4\u672A\u63D0\u4F9B"; const flag = metricFlagLabels[metric?.sourceFlag] ?? "\u7ED3\u679C\u5F85\u786E\u8BA4"; return `
  • ${name}${value}${unit}${range}${flag}
  • `; }; var renderReportCenter = (state) => { const filters = { family: ["ALL", "LAB", "EXAM"].includes(state?.reportFilters?.family) ? state.reportFilters.family : "ALL", status: ["ALL", "UNREAD", "READ"].includes(state?.reportFilters?.status) ? state.reportFilters.status : "ALL" }; const reports = selectReports(state, filters); return `
    ${pageHeader("\u5065\u5EB7\u6863\u6848", "\u62A5\u544A\u4E2D\u5FC3", "\u533B\u9662\u539F\u59CB\u62A5\u544A\u548C AI \u8F85\u52A9\u89E3\u8BFB\u7EDF\u4E00\u67E5\u770B\u3002")}

    \u5F53\u524D\u5C31\u8BCA\u4EBA ${escapeHtml(patientDisplayName(state))}

    ${[["ALL", "\u5168\u90E8"], ["LAB", "\u68C0\u9A8C\u62A5\u544A"], ["EXAM", "\u68C0\u67E5\u62A5\u544A"]].map(([id, label]) => ` `).join("")}
    ${[["ALL", "\u5168\u90E8"], ["UNREAD", "\u672A\u8BFB"], ["READ", "\u5DF2\u8BFB"]].map(([id, label]) => ` `).join("")}
    ${reports.length ? reports.map((report) => { const abnormalCount = abnormalMetricsOf(report).length; return ` `; }).join("") : `
    \u6682\u65E0\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u62A5\u544A

    \u53EF\u4EE5\u8C03\u6574\u62A5\u544A\u7C7B\u578B\u6216\u9605\u8BFB\u72B6\u6001\u3002

    `}
    `; }; var renderReportDetail = (report = {}, expanded = false) => { const metrics = Array.isArray(report?.metrics) ? report.metrics : []; const abnormalMetrics = abnormalMetricsOf(report); const hiddenMetrics = metrics.filter( (metric) => !abnormalMetrics.includes(metric) ); const visibleMetrics = expanded ? [...abnormalMetrics, ...hiddenMetrics] : abnormalMetrics; const reportId = report?.reportId ?? ""; return `

    \u533B\u9662\u539F\u59CB\u62A5\u544A

    ${escapeHtml(report?.title || "\u672A\u547D\u540D\u62A5\u544A")}

    ${escapeHtml(report?.hospitalName || "\u533B\u9662\u4FE1\u606F\u5F85\u786E\u8BA4")} \xB7 ${escapeHtml(report?.departmentName || "\u79D1\u5BA4\u5F85\u786E\u8BA4")}

    \u51FA\u5177\u65F6\u95F4\uFF1A${escapeHtml(report?.issuedAt || "\u5F85\u786E\u8BA4")}

    ${escapeHtml(reportSourceStatusLabels[report?.sourceStatus] ?? "\u62A5\u544A\u72B6\u6001\u5F85\u786E\u8BA4")}

    AI \u8F85\u52A9\u89E3\u8BFB\u4EC5\u4F9B\u53C2\u8003\uFF0C\u62A5\u544A\u7ED3\u679C\u9700\u7ED3\u5408\u75C7\u72B6\u3001\u75C5\u53F2\u5E76\u7531\u533B\u751F\u5224\u65AD\u3002

    \u6307\u6807\u6982\u89C8

    ${abnormalMetrics.length ? `${abnormalMetrics.length} \u9879\u5F02\u5E38\u6307\u6807` : "\u672A\u6807\u8BB0\u5F02\u5E38\u6307\u6807"}

    ${hiddenMetrics.length ? ` ` : ""}
    `; }; var safeReportText = (value, fallback) => typeof value === "string" && value.trim() ? escapeHtml(value.trim()) : fallback; var renderExaminationReportDetail = (report = {}) => { const reportId = typeof report?.reportId === "string" ? report.reportId : ""; return `

    \u533B\u9662\u68C0\u67E5\u62A5\u544A

    ${safeReportText(report?.title, "\u68C0\u67E5\u540D\u79F0\u5F85\u786E\u8BA4")}

    \u68C0\u67E5\u90E8\u4F4D\uFF1A${safeReportText(report?.bodyPart, "\u5F85\u786E\u8BA4")}

    ${safeReportText(report?.hospitalName, "\u533B\u9662\u4FE1\u606F\u5F85\u786E\u8BA4")} \xB7 ${safeReportText(report?.departmentName, "\u79D1\u5BA4\u5F85\u786E\u8BA4")}

    \u51FA\u5177\u65F6\u95F4\uFF1A${safeReportText(report?.issuedAt, "\u5F85\u786E\u8BA4")}

    \u68C0\u67E5\u6240\u89C1

    \u68C0\u67E5\u6240\u89C1

    ${safeReportText(report?.findings, "\u68C0\u67E5\u6240\u89C1\u5F85\u786E\u8BA4")}

    \u62A5\u544A\u7ED3\u8BBA

    \u62A5\u544A\u7ED3\u8BBA

    ${safeReportText(report?.conclusion, "\u62A5\u544A\u7ED3\u8BBA\u5F85\u786E\u8BA4")}

    \u62A5\u544A\u533B\u751F\uFF1A${safeReportText(report?.reportingDoctor, "\u62A5\u544A\u533B\u751F\u5F85\u786E\u8BA4")}

    \u5BA1\u6838\u72B6\u6001\uFF1A${safeReportText( report?.reviewStatus, reportSourceStatusLabels[report?.sourceStatus] ?? "\u5BA1\u6838\u72B6\u6001\u5F85\u786E\u8BA4" )}

    \u8BE5\u7C7B\u578B\u6682\u672A\u5F00\u653EAI\u8F85\u52A9\u89E3\u8BFB

    `; }; var renderOriginalReport = (report = {}) => { if (report?.family === "EXAM") { return `

    \u533B\u9662\u68C0\u67E5\u62A5\u544A\u539F\u4EF6

    ${safeReportText(report?.title, "\u68C0\u67E5\u540D\u79F0\u5F85\u786E\u8BA4")}

    ${safeReportText(report?.originalFormat, "\u56FE\u50CF\u6216PDF")}

    \u539F\u59CB\u56FE\u50CF\u6216PDF\u7531\u533B\u9662\u62A5\u544A\u7CFB\u7EDF\u63D0\u4F9B\uFF0C\u672C\u539F\u578B\u5C55\u793A\u7EDF\u4E00\u67E5\u770B\u5165\u53E3\u3002

    `; } const metrics = Array.isArray(report?.metrics) ? report.metrics : []; return `

    \u533B\u9662\u539F\u59CB\u62A5\u544A

    \u539F\u59CB\u62A5\u544A\u5185\u5BB9

    ${escapeHtml(report?.title || "\u672A\u547D\u540D\u62A5\u544A")}

    ${escapeHtml(report?.hospitalName || "\u533B\u9662\u4FE1\u606F\u5F85\u786E\u8BA4")} \xB7 ${escapeHtml(report?.departmentName || "\u79D1\u5BA4\u5F85\u786E\u8BA4")}

    \u51FA\u5177\u65F6\u95F4\uFF1A${escapeHtml(report?.issuedAt || "\u5F85\u786E\u8BA4")}

    `; }; var renderConsentOverlay = (state = {}) => { const reportId = state?.overlays?.reportId; const report = state?.reportSourceProjections?.[reportId]; return ` `; }; var commandPresentation = { PREPARED: { label: "\u51C6\u5907\u4E2D", icon: "loader-circle", tone: "pending" }, AWAITING_CONFIRMATION: { label: "\u5F85\u786E\u8BA4", icon: "shield-check", tone: "warning" }, EXECUTING: { label: "\u6267\u884C\u4E2D", icon: "loader-circle", tone: "pending" }, SUCCEEDED: { label: "\u6302\u53F7\u6210\u529F", icon: "circle-check-big", tone: "success" }, FAILED: { label: "\u6267\u884C\u5931\u8D25", icon: "circle-x", tone: "danger" }, EXPIRED: { label: "\u5DF2\u8FC7\u671F", icon: "clock-alert", tone: "danger" }, UNKNOWN: { label: "\u7ED3\u679C\u786E\u8BA4\u4E2D\uFF0C\u8BF7\u52FF\u91CD\u590D\u64CD\u4F5C", icon: "circle-help", tone: "warning" }, REJECTED: { label: "\u5DF2\u6682\u4E0D\u64CD\u4F5C", icon: "circle-minus", tone: "muted" } }; var renderCommandOverlay = (command) => { const presentation = commandPresentation[command?.status] ?? commandPresentation.PREPARED; const details = command?.details ?? {}; const statusLabel = command?.status === "SUCCEEDED" && !details.patientName ? "\u6A21\u62DF\u5B8C\u6210" : presentation.label; const awaiting = command?.status === "AWAITING_CONFIRMATION"; const canRequery = command?.status === "EXPIRED" || command?.status === "FAILED"; const canClose = command?.status === "SUCCEEDED" || command?.status === "REJECTED"; return ` `; }; var renderReportInterpreting = () => `

    AI \u8F85\u52A9\u89E3\u91CA

    \u6B63\u5728\u6574\u7406\u62A5\u544A\u89E3\u8BFB

    \u6B63\u5728\u7ED3\u5408\u53C2\u8003\u8303\u56F4\u6574\u7406\u4FBF\u4E8E\u7406\u89E3\u7684\u4FE1\u606F\uFF0C\u8BF7\u7A0D\u5019\u3002\u7ED3\u679C\u4EC5\u4F9B\u8F85\u52A9\u7406\u89E3\uFF0C\u4E0D\u4EE3\u8868\u8BCA\u65AD\u7ED3\u8BBA\u3002

    \u5206\u6790\u4ECD\u5728\u8FDB\u884C\uFF0C\u6682\u4E0D\u63D0\u4F9B\u786E\u5B9A\u6027\u7ED3\u8BBA
    `; var reportUnavailablePresentation = Object.freeze({ OCR_REVIEW_REQUIRED: Object.freeze({ title: "\u5F53\u524D\u62A5\u544A\u6682\u4E0D\u9002\u5408\u81EA\u52A8\u89E3\u8BFB", description: "\u62A5\u544A\u5185\u5BB9\u9700\u8981\u4EBA\u5DE5\u6838\u5BF9\uFF0C\u60A8\u4ECD\u53EF\u67E5\u770B\u533B\u9662\u539F\u59CB\u62A5\u544A\u3002", actions: Object.freeze([ Object.freeze({ action: "view-original-report", label: "\u67E5\u770B\u539F\u59CB\u62A5\u544A", tone: "primary" }), Object.freeze({ action: "contact-human-service", label: "\u8054\u7CFB\u4EBA\u5DE5\u670D\u52A1", tone: "secondary" }) ]) }), CRITICAL_NOTICE: Object.freeze({ title: "\u62A5\u544A\u542B\u533B\u9662\u5371\u6025\u63D0\u793A", description: "\u8BF7\u7ACB\u5373\u6309\u533B\u9662\u901A\u77E5\u8054\u7CFB\u533B\u52A1\u4EBA\u5458\uFF0C\u5E76\u4F18\u5148\u9075\u5FAA\u533B\u9662\u65E2\u6709\u5904\u7F6E\u6D41\u7A0B\u3002", actions: Object.freeze([ Object.freeze({ action: "contact-human-service", label: "\u7ACB\u5373\u8054\u7CFB\u4EBA\u5DE5\u670D\u52A1", tone: "primary" }), Object.freeze({ action: "view-original-report", label: "\u67E5\u770B\u539F\u59CB\u62A5\u544A", tone: "secondary" }) ]) }), AI_UNAVAILABLE: Object.freeze({ title: "AI\u8F85\u52A9\u89E3\u8BFB\u6682\u4E0D\u53EF\u7528", description: "\u533B\u9662\u539F\u59CB\u62A5\u544A\u4ECD\u53EF\u6B63\u5E38\u67E5\u770B\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002" }), REPORT_INVALIDATED: Object.freeze({ title: "\u533B\u9662\u5DF2\u66F4\u65B0\u6216\u64A4\u56DE\u62A5\u544A", description: "\u539FAI\u8F85\u52A9\u89E3\u91CA\u5DF2\u5931\u6548\u3002\u6700\u65B0\u7248\u672C\u5C1A\u672A\u540C\u6B65\u5B8C\u6210\uFF0C\u8BF7\u8FD4\u56DE\u62A5\u544A\u4E2D\u5FC3\u67E5\u770B\u72B6\u6001\u3002", actions: Object.freeze([ Object.freeze({ action: "open-report-center", label: "\u67E5\u770B\u62A5\u544A\u72B6\u6001", tone: "primary" }), Object.freeze({ action: "contact-human-service", label: "\u8054\u7CFB\u4EBA\u5DE5\u670D\u52A1", tone: "secondary" }) ]) }), UNSUPPORTED: Object.freeze({ title: "\u6682\u4E0D\u652F\u6301\u81EA\u52A8\u89E3\u8BFB", description: "\u60A8\u53EF\u4EE5\u67E5\u770B\u539F\u59CB\u62A5\u544A\u6216\u8054\u7CFB\u4EBA\u5DE5\u670D\u52A1\u3002" }) }); var renderReportUnavailable = ({ reason, reportId, serviceNotice } = {}) => { const presentation = Object.hasOwn(reportUnavailablePresentation, reason) ? reportUnavailablePresentation[reason] : reportUnavailablePresentation.UNSUPPORTED; const safeReportId = typeof reportId === "string" && /^[A-Za-z0-9._-]+$/.test(reportId) ? reportId : ""; const actions = presentation.actions ?? [ { action: "view-original-report", label: presentation.primaryActionLabel ?? "\u67E5\u770B\u539F\u59CB\u62A5\u544A", tone: "primary" }, { action: "contact-human-service", label: "\u8054\u7CFB\u4EBA\u5DE5\u670D\u52A1", tone: "secondary" } ]; return `

    ${escapeHtml(presentation.title)}

    ${escapeHtml(presentation.description)}

    ${typeof serviceNotice === "string" && serviceNotice ? `

    ${escapeHtml(serviceNotice)}

    ` : ""}
    ${actions.map(({ action, label, tone }) => ` `).join("")}
    `; }; var renderReportServiceOverlay = (state = {}) => { const reason = state?.overlays?.reportUnavailableReason; const presentation = Object.hasOwn(reportUnavailablePresentation, reason) ? reportUnavailablePresentation[reason] : reportUnavailablePresentation.UNSUPPORTED; return ` `; }; var renderReportInterpretationResult = (result, options = {}) => { const interpretation = result?.interpretation; if (!interpretation || typeof interpretation !== "object" || Array.isArray(interpretation)) { return ""; } const highlights = Array.isArray(interpretation.highlights) ? interpretation.highlights : []; const explanations = Array.isArray(interpretation.explanations) ? interpretation.explanations : []; const commonFactors = Array.isArray(interpretation.commonFactors) ? interpretation.commonFactors : explanations.map((item) => item?.commonFactors).filter(Boolean); const canDo = Array.isArray(interpretation.canDo) ? interpretation.canDo : []; const evidence = Array.isArray(interpretation.evidence) ? interpretation.evidence : []; const reportId = typeof result?.reportId === "string" ? result.reportId : ""; const reportAction = (action) => `data-action="${action}" data-report-id="${escapeHtml(reportId)}"`; const serviceNotice = typeof options?.serviceNotice === "string" ? options.serviceNotice : ""; const feedbackCategories = [ ["HELPFUL", "\u6709\u5E2E\u52A9"], ["METRIC_INACCURATE", "\u6307\u6807\u89E3\u91CA\u4E0D\u51C6\u786E"], ["HARD_TO_UNDERSTAND", "\u5185\u5BB9\u96BE\u7406\u89E3"], ["DIFFERS_FROM_DOCTOR", "\u4E0E\u533B\u751F\u8BF4\u660E\u4E0D\u4E00\u81F4"], ["OTHER", "\u5176\u4ED6\u95EE\u9898"] ]; return `

    AI \u8F85\u52A9\u89E3\u91CA \xB7 \u7ED3\u679C\u7248\u672C ${escapeHtml(result.resultVersion)}

    \u7ED3\u679C\u6982\u62EC

    ${escapeHtml(interpretation.headline)}

    ${escapeHtml(interpretation.summary)}

    \u5B89\u5168\u63D0\u793A

    ${escapeHtml(interpretation.safety)}

    \u9700\u8981\u5173\u6CE8

    \u6307\u6807\u89E3\u91CA

    ${explanations.map((item) => `

    ${escapeHtml(item.indicator)}

    ${escapeHtml(item.explanation)}

    `).join("")}

    \u5E38\u89C1\u76F8\u5173\u56E0\u7D20

    \u4E0A\u8FF0\u56E0\u7D20\u53EA\u662F\u5E2E\u52A9\u7406\u89E3\u6307\u6807\u7684\u5E38\u89C1\u60C5\u51B5\uFF0C\u4E0D\u4EE3\u8868\u4F60\u60A3\u6709\u76F8\u5E94\u75BE\u75C5\uFF0C\u4E5F\u4E0D\u80FD\u4F5C\u4E3A\u8BCA\u65AD\u7ED3\u679C\u3002

    \u53EF\u4EE5\u600E\u4E48\u505A

    \u5185\u5BB9\u4F9D\u636E

    \u7ED3\u679C\u7248\u672C ${escapeHtml(result.resultVersion)} \xB7 \u5BF9\u5E94\u5F53\u524D\u533B\u9662\u539F\u59CB\u62A5\u544A

    ${reportId ? `

    \u9700\u8981\u8FDB\u4E00\u6B65\u5E2E\u52A9

    ${serviceNotice ? `

    ${escapeHtml(serviceNotice)}

    ` : ""}
    ` : ""} ${reportId && options?.feedbackOpen ? `

    \u8FD9\u6B21\u89E3\u91CA\u5BF9\u4F60\u6709\u5E2E\u52A9\u5417\uFF1F

    \u8BF7\u9009\u62E9\u6700\u7B26\u5408\u7684\u4E00\u9879\uFF0C\u53CD\u9988\u4EC5\u7528\u4E8E\u6539\u8FDB\u672C\u6B21\u8F85\u52A9\u89E3\u91CA\u3002

    ` : ""} ${options?.feedbackSubmitted ? `

    \u611F\u8C22\u53CD\u9988\uFF0C\u5DF2\u8BB0\u5F55\u4F60\u7684\u9009\u62E9\u3002

    ` : ""}
    `; }; var renderQueueStatus = (state, appointmentId) => { const queue = (Array.isArray(state?.patientWorkItems) ? state.patientWorkItems : []).find((item) => item?.type === "WAITING_QUEUE" && item.appointmentId === appointmentId); if (!queue) { return `

    \u5019\u8BCA\u4FE1\u606F\u5F85\u66F4\u65B0

    \u5B8C\u6210\u7B7E\u5230\u540E\uFF0C\u6392\u961F\u53F7\u548C\u9884\u8BA1\u65F6\u95F4\u4F1A\u663E\u793A\u5728\u8FD9\u91CC\u3002

    `; } const updatedAt = typeof queue.updatedAt === "string" ? queue.updatedAt.slice(11, 16) : "\u5F85\u66F4\u65B0"; return `

    \u795E\u7ECF\u5185\u79D1 \xB7 \u5B9E\u65F6\u5019\u8BCA

    \u6392\u961F\u53F7 ${escapeHtml(queue.queueNumber ?? "\u5F85\u66F4\u65B0")}

    ${escapeHtml(queue.room ?? "\u8BCA\u5BA4\u5F85\u5206\u914D")}

    ${queue.delayed ? `
    \u5019\u8BCA\u65F6\u95F4\u53EF\u80FD\u5EF6\u540E\uFF0C\u8BF7\u7559\u610F\u53EB\u53F7\u66F4\u65B0\u3002
    ` : ""}
    \u524D\u65B9\u4EBA\u6570\u524D\u65B9 ${escapeHtml(queue.peopleAhead ?? 0)} \u4EBA
    \u9884\u8BA1\u65F6\u95F4\u9884\u8BA1\u7B49\u5F85 ${escapeHtml(queue.estimatedMinutes ?? 0)} \u5206\u949F

    \u5F53\u524D\u8BCA\u5BA4${escapeHtml(queue.room ?? "\u5F85\u5206\u914D")}

    \u961F\u5217\u66F4\u65B0\u65F6\u95F4${escapeHtml(updatedAt)}

    `; }; var renderRouteView = (location) => `

    \u9662\u5185\u8DEF\u7EBF

    ${escapeHtml(location ?? "\u95E8\u8BCA\u4E09\u697C\u795E\u7ECF\u5185\u79D1\u8BCA\u533A")}

    \u4ECE\u95E8\u8BCA\u5927\u5385\u4E58 2 \u53F7\u7535\u68AF\u81F3\u4E09\u697C\uFF0C\u51FA\u7535\u68AF\u540E\u53F3\u8F6C\u7EA6 30 \u7C73\u3002

    \u9884\u8BA1\u6B65\u884C4 \u5206\u949F

    \u65E0\u969C\u788D\u8DEF\u7EBF\u53EF\u7528

    `; var pageHeader = (eyebrow, title, description) => `

    ${eyebrow}

    ${title}

    ${description}

    `; var careGroupDefinitions = [ { title: "\u5F85\u529E\u7406", statuses: ["ACTION_REQUIRED", "UPCOMING"], fallback: "\u95E8\u8BCA\u8D39\u7528\u5F85\u786E\u8BA4" }, { title: "\u8FDB\u884C\u4E2D", statuses: ["IN_PROGRESS"], fallback: "\u4ECA\u65E5\u5C31\u533B\u65C5\u7A0B" }, { title: "\u5DF2\u5B8C\u6210", statuses: ["COMPLETED"], fallback: "\u8EAB\u4EFD\u4FE1\u606F\u5DF2\u6838\u9A8C" }, { title: "\u9700\u8981\u4EBA\u5DE5\u5904\u7406", statuses: ["MANUAL_REQUIRED"], fallback: "\u4EBA\u5DE5\u670D\u52A1\u968F\u65F6\u53EF\u7528" } ]; var renderCareOverview = (state) => { const items = Array.isArray(state?.patientWorkItems) ? state.patientWorkItems.filter((item) => item && typeof item === "object") : []; return `
    ${pageHeader("\u5C31\u533B\u603B\u89C8", "\u6211\u7684\u5C31\u533B", "\u6309\u529E\u7406\u72B6\u6001\u96C6\u4E2D\u67E5\u770B\u95E8\u8BCA\u3001\u68C0\u67E5\u548C\u8BCA\u540E\u4E8B\u9879\u3002")}
    ${careGroupDefinitions.map((group) => { const matches = items.filter((item) => group.statuses.includes(item.status)); const visible = matches.length > 0 ? matches : [{ title: group.fallback, description: "\u8FDB\u5165\u8BE6\u60C5\u67E5\u770B\u4E0B\u4E00\u6B65" }]; return `

    ${group.title}

    ${visible.length}
    ${visible.slice(0, 3).map((item) => `
    ${escapeHtml(item.title)}

    ${escapeHtml(item.description ?? "\u72B6\u6001\u548C\u53EF\u7528\u64CD\u4F5C\u6301\u7EED\u66F4\u65B0")}

    `).join("")}
    `; }).join("")}
    `; }; var recordEntries = [ { id: "lab-reports", label: "\u68C0\u9A8C\u62A5\u544A", meta: "\u8840\u5E38\u89C4 \xB7 3 \u9879\u5F02\u5E38", filter: "abnormal", icon: "flask-conical", action: "open-report-center", reportFamily: "LAB" }, { id: "exam-reports", label: "\u68C0\u67E5\u62A5\u544A", meta: "\u5F71\u50CF\u4E0E\u8D85\u58F0\u62A5\u544A", filter: "all", icon: "scan-line", action: "open-report-center", reportFamily: "EXAM" }, { id: "visits", label: "\u95E8\u8BCA\u8BB0\u5F55", meta: "\u5386\u6B21\u63A5\u8BCA\u4E0E\u8BCA\u540E\u8BB0\u5F55", filter: "all", icon: "notebook-tabs" }, { id: "medication", label: "\u5904\u65B9\u4E0E\u7528\u836F", meta: "\u5904\u65B9\u3001\u7528\u836F\u63D0\u9192", filter: "all", icon: "pill" }, { id: "allergies", label: "\u8FC7\u654F\u53F2", meta: "\u6682\u672A\u8BB0\u5F55\u836F\u7269\u8FC7\u654F", filter: "all", icon: "shield-alert" }, { id: "consents", label: "\u6388\u6743\u8BB0\u5F55", meta: "\u67E5\u770B\u548C\u64A4\u56DE\u6570\u636E\u6388\u6743", filter: "unread", icon: "file-lock-2" } ]; var renderRecords = (state) => { const activeFilter = ["all", "abnormal", "unread"].includes( state?.recordsFilter ) ? state.recordsFilter : "all"; const visible = activeFilter === "all" ? recordEntries : recordEntries.filter((entry) => entry.filter === activeFilter); return `
    ${pageHeader("\u5065\u5EB7\u6863\u6848", "\u6211\u7684\u5065\u5EB7\u8BB0\u5F55", "\u62A5\u544A\u3001\u95E8\u8BCA\u8BB0\u5F55\u548C\u6388\u6743\u4FE1\u606F\u7EDF\u4E00\u5F52\u6863\u3002")}
    ${[ ["all", "\u5168\u90E8"], ["abnormal", "\u5F02\u5E38"], ["unread", "\u672A\u89E3\u8BFB"] ].map(([id, label]) => ` `).join("")}
    ${visible.map((entry) => ` <${entry.action ? "button" : "article"} class="compact-row"${entry.action ? ` type="button" data-action="${entry.action}" data-filter="${entry.reportFamily}"` : ""}>
    ${entry.label}

    ${entry.meta}

    `).join("")}
    `; }; var profileEntries = [ ["\u5C31\u8BCA\u4EBA\u7BA1\u7406", "users-round"], ["\u6388\u6743\u4E2D\u5FC3", "shield-check"], ["\u6D88\u606F\u8BBE\u7F6E", "bell-ring"], ["\u5E38\u7528\u9662\u533A", "hospital"], ["\u533B\u4FDD\u548C\u652F\u4ED8", "badge-cent"], ["\u7535\u5B50\u7968\u636E", "receipt-text"], ["\u4EBA\u5DE5\u5BA2\u670D", "headphones"], ["\u5173\u4E8E AI", "sparkles"] ]; var renderProfile = () => `
    ${pageHeader("\u4E2A\u4EBA\u4E2D\u5FC3", "\u6211\u7684", "\u7BA1\u7406\u5C31\u8BCA\u4EBA\u3001\u9690\u79C1\u6388\u6743\u548C\u5E38\u7528\u670D\u52A1\u8BBE\u7F6E\u3002")}
    ${profileEntries.map(([label, icon]) => ` `).join("")}
    `; var messageCategories = ["\u62A5\u544A", "\u5C31\u533B", "\u7F34\u8D39", "\u968F\u8BBF", "\u7CFB\u7EDF"]; var renderMessages = (state) => { const messages = Array.isArray(state?.messages) ? state.messages.filter((message) => message && typeof message === "object") : []; return `
    ${pageHeader("\u6D88\u606F\u4E2D\u5FC3", "\u6D88\u606F", "\u6309\u670D\u52A1\u7C7B\u578B\u5B9A\u4F4D\u5230\u5BF9\u5E94\u5C31\u533B\u4E8B\u9879\uFF0C\u4E0D\u4F1A\u76F4\u63A5\u6267\u884C\u529E\u7406\u64CD\u4F5C\u3002")}
    ${messageCategories.map((category) => `${category}`).join("")}
    ${messages.length > 0 ? messages.map((message) => ` `).join("") : `
    \u6682\u65E0\u65B0\u6D88\u606F

    \u65B0\u7684\u62A5\u544A\u548C\u5C31\u533B\u63D0\u9192\u4F1A\u663E\u793A\u5728\u8FD9\u91CC\u3002

    `}
    `; }; var renderSystemState = (type, state) => { const cachedTaskCount = Array.isArray(state?.patientWorkItems) ? state.patientWorkItems.length : 0; const definitions = { INITIAL_LOADING: ["\u6B63\u5728\u52A0\u8F7D\u60A3\u8005\u670D\u52A1\u53F0", "\u6B63\u5728\u540C\u6B65\u6700\u65B0\u5C31\u533B\u4E8B\u9879\uFF0C\u8BF7\u7A0D\u5019\u3002", "loader-circle"], EMPTY: ["\u6682\u65E0\u76F8\u5173\u5185\u5BB9", "\u53EF\u4EE5\u8FD4\u56DE\u9996\u9875\u6216\u5C1D\u8BD5\u5176\u4ED6\u670D\u52A1\u3002", "inbox"], OFFLINE: ["\u7F51\u7EDC\u8FDE\u63A5\u4E0D\u53EF\u7528", `\u5DF2\u4FDD\u7559 ${cachedTaskCount} \u9879\u672C\u5730\u4EFB\u52A1\uFF0C\u8054\u7F51\u540E\u5C06\u81EA\u52A8\u66F4\u65B0\u3002`, "wifi-off"], DEGRADED: ["\u90E8\u5206\u667A\u80FD\u670D\u52A1\u6682\u4E0D\u53EF\u7528", "\u57FA\u7840\u5C31\u533B\u4E8B\u9879\u4ECD\u53EF\u67E5\u770B\uFF0C\u4E5F\u53EF\u4EE5\u8054\u7CFB\u4EBA\u5DE5\u670D\u52A1\u3002", "shield-alert"], QUERY_FAILED: ["\u67E5\u8BE2\u5931\u8D25", "\u8BF7\u7A0D\u540E\u91CD\u65B0\u67E5\u8BE2\uFF0C\u65E7\u7ED3\u679C\u4E0D\u4F1A\u7528\u4E8E\u7EE7\u7EED\u529E\u7406\u3002", "search-x"], COMMAND_FAILED: ["\u529E\u7406\u5931\u8D25", "\u672C\u6B21\u64CD\u4F5C\u672A\u5B8C\u6210\uFF0C\u8BF7\u91CD\u65B0\u67E5\u8BE2\u6216\u8054\u7CFB\u4EBA\u5DE5\u670D\u52A1\u3002", "circle-x"], COMMAND_UNKNOWN: ["\u7ED3\u679C\u786E\u8BA4\u4E2D\uFF0C\u8BF7\u52FF\u91CD\u590D\u64CD\u4F5C", "\u6B63\u5728\u6838\u9A8C\u533B\u9662\u7CFB\u7EDF\u7ED3\u679C\uFF0C\u53EF\u4EE5\u7A0D\u540E\u67E5\u770B\u72B6\u6001\u3002", "circle-ellipsis"] }; const [title, description, icon] = definitions[type] ?? definitions.EMPTY; return `

    ${title}

    ${description}

    `; }; var renderScenarioPanel = (state) => { const activeScenario = demoScenarios.includes(state?.demoScenario) ? state.demoScenario : "EMPTY_HOME"; const activeTask = state?.activeAgentTaskProjection; const commands = Object.values(state?.commandProjections ?? {}); const latestFixture = state?.appliedProjectionFixtureIds?.at?.(-1) ?? "\u65E0"; const renderScenarioGroup = (groupId, title, scenarios) => `

    ${title}

    ${scenarios.map((scenario) => ` `).join("")}
    `; return `

    \u65B9\u6848\u6F14\u793A

    ${escapeHtml(scenarioLabels[activeScenario])}
    ${renderScenarioGroup( "reportClosureScenarios", "\u62A5\u544A\u95ED\u73AF", demoScenarioGroups.REPORT_CLOSURE )} ${renderScenarioGroup( "careClosureScenarios", "\u5C31\u533B\u95ED\u73AF", demoScenarioGroups.CARE_CLOSURE )}
    \u5F53\u524D fixture
    ${escapeHtml(latestFixture)}
    Agent task
    ${escapeHtml(activeTask ? `${activeTask.type}/${activeTask.stage}` : "\u65E0")}
    PatientWorkItem
    ${escapeHtml(state?.patientWorkItems?.length ?? 0)} \u9879
    Command
    ${escapeHtml(commands.map((item) => `${item.commandId}/${item.status}`).join(", ") || "\u65E0")}

    \u2190/\u2192 \u5207\u6362 \xB7 R \u91CD\u7F6E \xB7 P \u663E\u793A/\u9690\u85CF

    `; }; var renderCurrentView = (state) => { const { reportId, reportView } = state?.overlays ?? {}; if (state?.systemState === "AI_INTERPRETING") { return renderReportInterpreting(); } if (state?.systemState) { return renderSystemState(state.systemState, state); } if (state?.overlays?.journeyView === "CHECKIN_CONFIRMATION") { return `

    \u5230\u9662\u7B7E\u5230

    \u8BF7\u786E\u8BA4\u672C\u4EBA\u5DF2\u5230\u8FBE\u8BCA\u533A

    \u7B7E\u5230\u9700\u8981\u60A3\u8005\u660E\u786E\u786E\u8BA4\uFF1B\u672C\u9875\u9762\u4E0D\u4F1A\u6839\u636E\u4F4D\u7F6E\u81EA\u52A8\u5B8C\u6210\u7B7E\u5230\u3002

    \u786E\u8BA4\u540E\u4ECD\u4EE5\u533B\u9662\u7B7E\u5230\u63A5\u53E3\u8FD4\u56DE\u7ED3\u679C\u4E3A\u51C6\u3002

    `; } if (state?.overlays?.journeyView === "ROUTE") { const journey = state.journeyProjections?.find( (item) => item?.appointmentId === state.overlays.appointmentId ); const checkin = state.patientWorkItems?.find( (item) => item?.type === "CHECK_IN" && item.appointmentId === state.overlays.appointmentId ); return renderRouteView( journey?.location ?? checkin?.location ?? journey?.room ); } if (state?.overlays?.journeyView === "QUEUE" && state?.overlays?.appointmentId) { return renderQueueStatus(state, state.overlays.appointmentId); } if (reportView === "REPORT_DETAIL" && reportId) { const report = state.reportSourceProjections?.[reportId]; return report?.family === "EXAM" ? renderExaminationReportDetail(report) : renderReportDetail(report, Boolean(state.overlays.reportExpanded)); } if (reportView === "ORIGINAL_REPORT" && reportId) { return renderOriginalReport(state.reportSourceProjections?.[reportId]); } if (reportView === "REPORT_UNAVAILABLE" && reportId) { return renderReportUnavailable({ reason: state?.overlays?.reportUnavailableReason, reportId, serviceNotice: state?.overlays?.reportServiceNotice }); } if (reportView === "INTERPRETING" && reportId) { return renderReportInterpreting(); } if (reportView === "INTERPRETED" && hasValidReportConsent(state, reportId)) { return renderReportInterpretationResult( selectValidReportResult(state, reportId), { feedbackOpen: state?.overlays?.reportFeedbackOpen === true, feedbackSubmitted: state?.overlays?.reportFeedbackSubmitted === true, serviceNotice: state?.overlays?.reportServiceNotice } ); } if (state?.activeTab === "assistant") { return renderAssistant(state); } if (state?.activeTab === "care") { return renderCareOverview(state); } if (state?.activeTab === "records") { return state?.overlays?.reportView === "REPORT_CENTER" ? renderReportCenter(state) : renderRecords(state); } if (state?.activeTab === "profile") { return renderProfile(state); } if (state?.activeTab === "messages") { return renderMessages(state); } return renderHome(state); }; var modalOverlayIdentity = null; var modalOverlayDocument = null; var consentFocusReturn = null; var scenarioPanelVisible = true; var demoViewport = "390"; var hasConsentDialog = (state) => typeof state?.overlays?.consentId === "string" && state.overlays.consentId.startsWith("consent-ai-"); var hasCommandDialog = (state) => Boolean( state?.overlays?.commandId && state?.commandProjections?.[state.overlays.commandId]?.status === "AWAITING_CONFIRMATION" ); var hasReportServiceDialog = (state) => state?.overlays?.reportView === "REPORT_UNAVAILABLE" && state?.overlays?.reportServiceNotice === "\u5DF2\u4E3A\u4F60\u6253\u5F00\u4EBA\u5DE5\u670D\u52A1\u5165\u53E3\u3002"; var focusModalDialog = (overlayRoot) => { const dialog = overlayRoot?.querySelector?.('[role="dialog"]'); const firstButton = dialog?.querySelector?.("button"); (firstButton ?? dialog)?.focus?.(); }; var restoreConsentFocus = (root, elements) => { const matchingTrigger = Array.from( root?.querySelectorAll?.('[data-action="interpret-report"]') ?? [] ).find((trigger) => trigger.dataset?.reportId === consentFocusReturn?.reportId); const fallback = elements.appView.querySelector?.( "button, [href], [tabindex]" ) ?? elements.appView; (matchingTrigger ?? fallback)?.focus?.(); consentFocusReturn = null; }; var renderAppShell = (state = createInitialState()) => { const root = globalThis.document; const elements = getShellElements(root); if (!elements) { return false; } if (root !== modalOverlayDocument) { modalOverlayIdentity = null; modalOverlayDocument = root; } elements.appHeader.innerHTML = renderHeader(state); elements.appView.innerHTML = renderCurrentView(state); elements.bottomNav.innerHTML = navItems.map( ({ id, label, icon }) => ` ` ).join(""); const scenarioPanel = root?.getElementById?.("scenarioPanel"); const phoneShell = root?.querySelector?.(".phone-shell"); if (scenarioPanel) { scenarioPanel.innerHTML = renderScenarioPanel(state); scenarioPanel.hidden = !scenarioPanelVisible; } if (phoneShell?.dataset) { phoneShell.dataset.viewport = demoViewport; } const overlayRoot = root?.getElementById?.("overlayRoot"); const hasConsentOverlay = Boolean(overlayRoot) && hasConsentDialog(state); const activeCommand = state?.overlays?.commandId ? state?.commandProjections?.[state.overlays.commandId] : null; const hasCommandOverlay = Boolean(overlayRoot) && hasCommandDialog(state); const hasReportServiceOverlay = Boolean(overlayRoot) && hasReportServiceDialog(state); const nextModalIdentity = hasConsentOverlay ? `consent:${state.overlays.consentId}` : hasCommandOverlay ? `command:${activeCommand.commandId}:${activeCommand.status}` : hasReportServiceOverlay ? `report-service:${state.overlays.reportId}` : null; const hasModalOverlay = Boolean(nextModalIdentity); for (const element of [ elements.appHeader, elements.appView, elements.bottomNav, scenarioPanel ]) { if (!element) { continue; } element.inert = hasModalOverlay; element.setAttribute?.( "aria-hidden", hasModalOverlay ? "true" : "false" ); } if (overlayRoot) { overlayRoot.innerHTML = hasConsentOverlay ? renderConsentOverlay(state) : hasCommandOverlay ? renderCommandOverlay(activeCommand) : hasReportServiceOverlay ? renderReportServiceOverlay(state) : ""; if (nextModalIdentity && nextModalIdentity !== modalOverlayIdentity) { focusModalDialog(overlayRoot); } else if (!nextModalIdentity && modalOverlayIdentity) { restoreConsentFocus(root, elements); } } modalOverlayIdentity = nextModalIdentity; renderIcons(); return true; }; var demoState = loadScenario(createInitialState(), "EMPTY_HOME"); var boundDocuments = /* @__PURE__ */ new WeakSet(); var reportProjectionGeneration = 0; var activeReportProjectionTimer = null; var registrationSelectionFixtureSequence = 0; var commandConfirmationInFlight = null; var lastCommandConfirmationRequest = null; var commandRejectionInFlight = null; var lastCommandRejectionRequest = null; var getDemoState = () => demoState; var getLastCommandConfirmationRequest = () => lastCommandConfirmationRequest; var getLastCommandRejectionRequest = () => lastCommandRejectionRequest; var simulateCandidateSelectionBackendFixture = (state, interaction) => { registrationSelectionFixtureSequence += 1; const task = state?.activeAgentTaskProjection; const result = task?.activeResultRef ? state?.resultSnapshotProjections?.[task.activeResultRef] : null; const now = Date.parse(state?.demoNow); const expiresAt = Date.parse(result?.expiresAt); const versionMatched = interaction?.resultRef === result?.resultRef && interaction?.resultVersion === result?.resultVersion; const notExpired = Number.isFinite(now) && Number.isFinite(expiresAt) && expiresAt > now; const realtimeAvailable = Array.isArray(result?.items) && result.items.some( (item) => item?.candidateId === interaction?.candidateId ); const errorCode = !notExpired ? "RESULT_EXPIRED" : !versionMatched ? "RESULT_VERSION_CONFLICT" : !realtimeAvailable ? "SLOT_UNAVAILABLE" : null; const fixtureId = `selection-response-${registrationSelectionFixtureSequence}`; if (errorCode) { return { id: fixtureId, errorCode, validation: { tenantMatched: true, patientMatched: true, sessionMatched: true, versionMatched, notExpired, realtimeAvailable, l1LockSucceeded: false } }; } const lockExpiresAt = new Date( Math.min(now + 5 * 60 * 1e3, expiresAt - 1) ).toISOString(); return { id: fixtureId, outcome: "SUCCESS", ...interaction, validation: { tenantMatched: true, patientMatched: true, sessionMatched: true, versionMatched, notExpired, realtimeAvailable, l1LockSucceeded: true }, lock: { lockId: `appointment-lock-${registrationSelectionFixtureSequence}`, expiresAt: lockExpiresAt } }; }; var submitAssistantText = (state, text) => { const normalizedText = typeof text === "string" ? text.trim() : text; const interaction = buildCandidateSelectionInteraction( state, normalizedText ); if (!interaction && !(normalizedText === "\u9009\u7B2C\u4E00\u4E2A" && state?.activeAgentTaskProjection?.type === "REGISTRATION")) { return submitInteraction(state, normalizedText); } const responseFixture = simulateCandidateSelectionBackendFixture( state, interaction ); const selectedState = applyCandidateSelectionResponseFixture( state, responseFixture ); return applyRegistrationCommandBackendFixture(selectedState); }; var applyRegistrationCommandBackendFixture = (state) => { const task = state?.activeAgentTaskProjection; const result = state?.resultSnapshotProjections?.[task?.activeResultRef]; const selected = result?.items?.find( (item) => item?.candidateId === task?.selectedCandidateId ); if (task?.stage !== "AWAITING_REGISTRATION_CONFIRMATION" || !selected) { return state; } const commands = Object.values(state?.commandProjections ?? {}); const nonTerminalStatuses = /* @__PURE__ */ new Set([ "PREPARED", "AWAITING_CONFIRMATION", "EXECUTING", "UNKNOWN" ]); const existing = commands.find((command) => command?.details?.candidateId === selected.candidateId && nonTerminalStatuses.has(command.status)); if (existing) { return { ...state, overlays: { ...state.overlays, commandId: existing.commandId } }; } const nextSequence = commands.reduce((highest, command) => { const sequence = Number.parseInt( command?.commandId?.match(/^command-register-(\d+)$/)?.[1], 10 ); return Number.isInteger(sequence) ? Math.max(highest, sequence) : highest; }, 0) + 1; const commandId = `command-register-${String(nextSequence).padStart(3, "0")}`; return applyCommandProjectionFixture(state, { id: `command-awaiting-${commandId}`, commandId, version: 1, riskLevel: "L2", status: "AWAITING_CONFIRMATION", details: { operationName: "\u786E\u8BA4\u6302\u53F7", patientName: "\u5F20\u5148\u751F", departmentName: selected.departmentName, doctorName: selected.doctorName, doctorTitle: selected.doctorTitle, visitAt: `${selected.visitDate} ${selected.visitTime}`, fee: selected.fee, expiresAt: task.lock?.expiresAt, countdown: "\u5269\u4F59 5 \u5206\u949F", candidateId: selected.candidateId } }); }; var reduceDemoAction = (state, action, reportId, candidateId, assistantText, appointmentId, tabId, filter, messageId, scenarioName, viewport) => { switch (action) { case "view-report": return openReportDetails(state, reportId); case "view-original-report": return state.reportSourceProjections?.[reportId] ? { ...state, overlays: { ...state.overlays, reportId, reportView: "ORIGINAL_REPORT" } } : state; case "open-report-center": { const reportCenterState = closeReportView(state); return { ...reportCenterState, activeTab: "records", reportFilters: { ...reportCenterState.reportFilters, family: ["LAB", "EXAM"].includes(filter) ? filter : "ALL" }, overlays: { ...reportCenterState.overlays, reportView: "REPORT_CENTER" } }; } case "set-report-family-filter": return { ...state, activeTab: "records", reportFilters: { ...state.reportFilters, family: ["ALL", "LAB", "EXAM"].includes(filter) ? filter : "ALL" } }; case "set-report-status-filter": return { ...state, activeTab: "records", reportFilters: { ...state.reportFilters, status: ["ALL", "UNREAD", "READ"].includes(filter) ? filter : "ALL" } }; case "toggle-report-metrics": return { ...state, overlays: { ...state.overlays, reportExpanded: !state.overlays?.reportExpanded } }; case "interpret-report": return requestReportInterpretation(state, reportId); case "grant-report-consent": return grantConsent(state, state?.overlays?.consentId); case "reject-report-consent": return rejectConsent(state, state?.overlays?.consentId); case "open-report-feedback": return reportId === state?.overlays?.reportId && state?.overlays?.reportView === "INTERPRETED" && hasValidReportConsent(state, reportId) && selectValidReportResult(state, reportId) ? { ...state, overlays: { ...state.overlays, reportFeedbackOpen: true, reportFeedbackSubmitted: false, reportServiceNotice: null } } : state; case "submit-report-feedback": { if (reportId !== state?.overlays?.reportId || state?.overlays?.reportView !== "INTERPRETED") { return state; } const feedbackState = submitReportFeedback(state, { reportId, category: filter }); return feedbackState === state ? state : { ...feedbackState, overlays: { ...feedbackState.overlays, reportFeedbackOpen: false, reportFeedbackSubmitted: true, reportServiceNotice: null } }; } case "consult-ordering-doctor": case "online-consultation": case "contact-human-service": { if (action === "contact-human-service" && reportId === state?.overlays?.reportId && state?.overlays?.reportView === "REPORT_UNAVAILABLE" && state?.reportSourceProjections?.[reportId]) { return { ...state, overlays: { ...state.overlays, reportServiceNotice: "\u5DF2\u4E3A\u4F60\u6253\u5F00\u4EBA\u5DE5\u670D\u52A1\u5165\u53E3\u3002" } }; } if (reportId !== state?.overlays?.reportId || state?.overlays?.reportView !== "INTERPRETED" || !hasValidReportConsent(state, reportId) || !selectValidReportResult(state, reportId)) { return state; } const notices = { "consult-ordering-doctor": "\u5DF2\u4E3A\u4F60\u6253\u5F00\u5F00\u5355\u533B\u751F\u54A8\u8BE2\u5165\u53E3\u3002", "online-consultation": "\u5DF2\u4E3A\u4F60\u6253\u5F00\u5728\u7EBF\u54A8\u8BE2\u5165\u53E3\u3002", "contact-human-service": "\u5DF2\u4E3A\u4F60\u6253\u5F00\u4EBA\u5DE5\u670D\u52A1\u5165\u53E3\u3002" }; return { ...state, overlays: { ...state.overlays, reportFeedbackOpen: false, reportServiceNotice: notices[action] } }; } case "close-report-service": return hasReportServiceDialog(state) ? { ...state, overlays: { ...state.overlays, reportServiceNotice: null } } : state; case "revoke-report-consent": { const activeReportId = state?.overlays?.reportId; const activeConsentId = typeof activeReportId === "string" ? `consent-ai-${activeReportId}` : Object.keys(state?.consents ?? {}).find( (consentId) => state.consents[consentId]?.status === "GRANTED" ); return revokeConsent(state, activeConsentId); } case "go-home": { const homeState = closeReportView(state); return { ...homeState, activeTab: "home", overlays: { ...homeState.overlays, appointmentId: null, journeyView: null } }; } case "open-checkin-confirmation": return { ...state, overlays: { ...state.overlays, appointmentId, journeyView: "CHECKIN_CONFIRMATION" } }; case "open-queue": return { ...state, overlays: { ...state.overlays, appointmentId, journeyView: "QUEUE" } }; case "open-route": return { ...state, overlays: { ...state.overlays, appointmentId, journeyView: "ROUTE" } }; case "switch-patient": { commandConfirmationInFlight = null; commandRejectionInFlight = null; invalidateReportProjectionTimer(); const nextPatientId = state.activePatientId === "patient-li-na" ? "patient-zhang-san" : "patient-li-na"; return { ...createInitialState({ activePatientId: nextPatientId }), demoScenario: "EMPTY_HOME" }; } case "submit-checkin": { const checkedIn = applyServerProjectionFixture(state, { id: `checkin-completed-${appointmentId}`, type: "CHECKIN_COMPLETED", occurredAt: state.demoNow, payload: { appointmentId, queueNumber: "A023", room: "3F-08\u8BCA\u5BA4" } }); return { ...checkedIn, overlays: { ...checkedIn.overlays, appointmentId, journeyView: "QUEUE" } }; } case "open-assistant": case "return-current-task": return { ...closeReportView(state), activeTab: "assistant" }; case "navigate-tab": { const tabState = closeReportView(state); return { ...tabState, activeTab: navItems.some((item) => item.id === tabId) ? tabId : "home", systemState: null, overlays: { ...tabState.overlays, appointmentId: null, journeyView: null } }; } case "open-messages": return { ...closeReportView(state), activeTab: "messages", systemState: null }; case "set-record-filter": return { ...state, activeTab: "records", recordsFilter: ["all", "abnormal", "unread"].includes(filter) ? filter : "all" }; case "open-message": { const message = (Array.isArray(state.messages) ? state.messages : []).find((item) => item?.id === messageId); if (message?.type === "REPORT") { const reportId2 = typeof message.reportId === "string" ? message.reportId : null; return reportId2 ? openReportDetails(state, reportId2) : state; } if (message?.type === "JOURNEY") { const journey = state.journeyProjections?.[0]; return journey ? { ...state, activeTab: journey.stage === "QUEUE_WAITING" ? state.activeTab : "care", overlays: { ...state.overlays, appointmentId: journey.appointmentId, journeyView: journey.stage === "QUEUE_WAITING" ? "QUEUE" : null } } : state; } return state; } case "load-scenario": case "reset-scenario": { commandConfirmationInFlight = null; commandRejectionInFlight = null; invalidateReportProjectionTimer(); return loadScenario( state, action === "reset-scenario" ? state.demoScenario ?? "EMPTY_HOME" : scenarioName ); } case "previous-scenario": case "next-scenario": { const currentIndex = Math.max( 0, demoScenarios.indexOf(state.demoScenario) ); const delta = action === "previous-scenario" ? -1 : 1; const nextIndex = (currentIndex + delta + demoScenarios.length) % demoScenarios.length; commandConfirmationInFlight = null; commandRejectionInFlight = null; invalidateReportProjectionTimer(); return loadScenario(state, demoScenarios[nextIndex]); } case "toggle-scenario-panel": scenarioPanelVisible = !scenarioPanelVisible; return state; case "set-demo-viewport": demoViewport = viewport === "430" ? "430" : "390"; return state; case "submit-registration-demo": return submitAssistantText( state, "\u6211\u60F3\u6302\u660E\u5929\u795E\u7ECF\u5185\u79D1\u674E\u660E\u4E3B\u4EFB\u7684\u53F7" ); case "submit-assistant-text": return submitAssistantText(state, assistantText); case "select-candidate": { const interaction = buildCandidateSelectionInteraction( state, candidateId ); return applyRegistrationCommandBackendFixture( applyCandidateSelectionResponseFixture( state, simulateCandidateSelectionBackendFixture(state, interaction) ) ); } case "close-command": return { ...state, activeTab: "home", overlays: { ...state.overlays, commandId: null } }; case "requery-registration": commandConfirmationInFlight = null; return submitInteraction({ ...state, overlays: { ...state.overlays, commandId: null } }, "\u6211\u60F3\u6302\u660E\u5929\u795E\u7ECF\u5185\u79D1\u674E\u660E\u4E3B\u4EFB\u7684\u53F7"); default: return state; } }; var selectInterpretingReportId = (state) => { const reportId = state?.overlays?.reportId; const hasInterpretingItem = state?.patientWorkItems?.some( (item) => item?.type === "REPORT_REVIEW" && item.reportId === reportId && item.stage === "INTERPRETING" ); return typeof reportId === "string" && state?.overlays?.reportView === "INTERPRETING" && evaluateReportInterpretationGate(state, reportId).allowed && state?.reportSourceProjections?.[reportId]?.interpretationStatus === "GENERATING" && hasValidReportConsent(state, reportId) && hasInterpretingItem ? reportId : null; }; var invalidateReportProjectionTimer = () => { activeReportProjectionTimer = null; reportProjectionGeneration += 1; }; var ensureReportInterpretationProjection = () => { if (demoState?.demoScenario === "REPORT_GENERATING") { invalidateReportProjectionTimer(); return; } const reportId = selectInterpretingReportId(demoState); if (!reportId) { invalidateReportProjectionTimer(); return; } if (activeReportProjectionTimer?.reportId === reportId && activeReportProjectionTimer.generation === reportProjectionGeneration) { return; } if (typeof globalThis.setTimeout !== "function") { return; } const scheduledGeneration = reportProjectionGeneration; const consentId = `consent-ai-${reportId}`; const timerToken = { generation: scheduledGeneration, reportId, patientId: demoState?.activePatientId, stateContext: demoState, consentContext: demoState?.consents?.[consentId], bindingContext: demoState?.consentScopeBindings }; activeReportProjectionTimer = timerToken; globalThis.setTimeout(() => { if (activeReportProjectionTimer !== timerToken) { return; } activeReportProjectionTimer = null; const isCurrentInterpretation = reportProjectionGeneration === scheduledGeneration && selectInterpretingReportId(demoState) === reportId && demoState?.activePatientId === timerToken.patientId && demoState === timerToken.stateContext && demoState?.consents?.[consentId] === timerToken.consentContext && demoState?.consentScopeBindings === timerToken.bindingContext; if (!isCurrentInterpretation) { return; } demoState = applyReportInterpretationProjectionFixture( demoState, reportId ); renderAppShell(demoState); }, 120); }; var beginCommandConfirmation = () => { const commandId = demoState?.overlays?.commandId; if (commandConfirmationInFlight || commandRejectionInFlight || !commandId) { return; } lastCommandConfirmationRequest = buildCommandConfirmationRequest( demoState, commandId, { channel: "CARD", idempotencyKey: `confirm-${commandId.replace(/^command-/, "")}` } ); const token = { commandId, request: lastCommandConfirmationRequest }; commandConfirmationInFlight = token; if (typeof globalThis.setTimeout !== "function") { return; } globalThis.setTimeout(() => { if (commandConfirmationInFlight !== token || demoState?.commandProjections?.[commandId]?.status !== "AWAITING_CONFIRMATION") { return; } demoState = applyCommandProjectionFixture(demoState, { id: `command-executing-${commandId}`, commandId, version: demoState.commandProjections[commandId].version + 1, status: "EXECUTING" }); renderAppShell(demoState); globalThis.setTimeout(() => { if (commandConfirmationInFlight !== token || demoState?.commandProjections?.[commandId]?.status !== "EXECUTING") { return; } demoState = applyCommandProjectionFixture(demoState, { id: `command-succeeded-${commandId}`, commandId, version: demoState.commandProjections[commandId].version + 1, status: "SUCCEEDED", result: { type: "APPOINTMENT_CREATED", eventId: `appointment-event-${commandId}`, appointmentId: `appointment-${commandId}`, patientId: demoState.activePatientId, summary: { visitDate: demoState.commandProjections[commandId].details?.visitAt?.split(" ")?.[0], visitTime: demoState.commandProjections[commandId].details?.visitAt?.split(" ")?.[1], departmentName: demoState.commandProjections[commandId].details?.departmentName, doctorName: demoState.commandProjections[commandId].details?.doctorName, doctorTitle: demoState.commandProjections[commandId].details?.doctorTitle, fee: demoState.commandProjections[commandId].details?.fee } } }); commandConfirmationInFlight = null; renderAppShell(demoState); }, 120); }, 80); }; var beginCommandRejection = () => { const commandId = demoState?.overlays?.commandId; if (commandRejectionInFlight || commandConfirmationInFlight || !commandId) { return; } lastCommandRejectionRequest = buildCommandRejectionRequest( demoState, commandId, { reason: "\u6682\u4E0D\u64CD\u4F5C", idempotencyKey: `reject-${commandId.replace(/^command-/, "")}` } ); const token = { commandId, request: lastCommandRejectionRequest }; commandRejectionInFlight = token; if (typeof globalThis.setTimeout !== "function") { return; } globalThis.setTimeout(() => { if (commandRejectionInFlight !== token || demoState?.commandProjections?.[commandId]?.status !== "AWAITING_CONFIRMATION") { return; } demoState = applyCommandProjectionFixture(demoState, { id: `command-rejected-${commandId}`, commandId, version: demoState.commandProjections[commandId].version + 1, status: "REJECTED" }); commandRejectionInFlight = null; renderAppShell(demoState); }, 80); }; var initializePatientServiceDesk = (state = demoState) => { if (state !== demoState) { invalidateReportProjectionTimer(); commandConfirmationInFlight = null; commandRejectionInFlight = null; lastCommandConfirmationRequest = null; lastCommandRejectionRequest = null; } demoState = state; const root = globalThis.document; if (root?.addEventListener && !boundDocuments.has(root)) { root.addEventListener("click", (event) => { const trigger = event.target?.closest?.("[data-action]"); const overlayRoot = root.getElementById?.("overlayRoot"); const appView = root.getElementById?.("appView"); const scenarioPanel = root.getElementById?.("scenarioPanel"); const appShell = root.querySelector?.(".phone-shell") ?? appView?.closest?.(".phone-shell"); const withinApp = Boolean( appShell?.contains?.(trigger) || appView?.contains?.(trigger) || overlayRoot?.contains?.(trigger) || scenarioPanel?.contains?.(trigger) ); if (!trigger || !withinApp) { return; } if ((hasConsentDialog(demoState) || hasCommandDialog(demoState) || hasReportServiceDialog(demoState)) && scenarioPanel?.contains?.(trigger)) { return; } if (trigger.dataset?.action === "interpret-report") { consentFocusReturn = { reportId: trigger.dataset?.reportId }; } if (trigger.dataset?.action === "confirm-command") { beginCommandConfirmation(); return; } if (trigger.dataset?.action === "reject-command") { beginCommandRejection(); return; } demoState = reduceDemoAction( demoState, trigger.dataset?.action, trigger.dataset?.reportId, trigger.dataset?.candidateId, root.getElementById?.("assistantComposerInput")?.value, trigger.dataset?.appointmentId, trigger.dataset?.tabId, trigger.dataset?.filter, trigger.dataset?.messageId, trigger.dataset?.scenario, trigger.dataset?.viewport ); renderAppShell(demoState); ensureReportInterpretationProjection(); }); root.addEventListener("keydown", (event) => { if (event.key === "Enter" && event.target?.id === "assistantComposerInput") { const appView = root.getElementById?.("appView"); if (!appView?.contains?.(event.target)) { return; } event.preventDefault?.(); demoState = reduceDemoAction( demoState, "submit-assistant-text", void 0, void 0, event.target.value ); renderAppShell(demoState); ensureReportInterpretationProjection(); return; } const targetTag = event.target?.tagName?.toLowerCase?.(); const isTyping = ["input", "textarea", "select"].includes(targetTag) || event.target?.isContentEditable; const isPresentationShortcut = !isTyping && ["ArrowLeft", "ArrowRight", "r", "R", "p", "P"].includes(event.key); const consentDialogOpen = hasConsentDialog(demoState); const commandDialogOpen = hasCommandDialog(demoState); const reportServiceDialogOpen = hasReportServiceDialog(demoState); if (isPresentationShortcut && (consentDialogOpen || commandDialogOpen || reportServiceDialogOpen)) { event.preventDefault?.(); return; } if (isPresentationShortcut) { event.preventDefault?.(); if (event.key === "p" || event.key === "P") { scenarioPanelVisible = !scenarioPanelVisible; renderAppShell(demoState); return; } const currentIndex = Math.max( 0, demoScenarios.indexOf(demoState.demoScenario) ); const nextScenario = event.key === "r" || event.key === "R" ? demoState.demoScenario ?? "EMPTY_HOME" : demoScenarios[(currentIndex + (event.key === "ArrowLeft" ? -1 : 1) + demoScenarios.length) % demoScenarios.length]; initializePatientServiceDesk(loadScenario(demoState, nextScenario)); return; } if (!consentDialogOpen && !commandDialogOpen && !reportServiceDialogOpen) { return; } if (event.key === "Escape" && reportServiceDialogOpen) { event.preventDefault?.(); demoState = reduceDemoAction( demoState, "close-report-service" ); renderAppShell(demoState); return; } if (event.key === "Escape" && consentDialogOpen) { event.preventDefault?.(); demoState = rejectConsent( demoState, demoState.overlays.consentId ); renderAppShell(demoState); ensureReportInterpretationProjection(); return; } if (event.key !== "Tab") { return; } const overlayRoot = root.getElementById?.("overlayRoot"); const focusables = Array.from( overlayRoot?.querySelectorAll?.( 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])' ) ?? [] ); if (focusables.length === 0) { event.preventDefault?.(); overlayRoot?.querySelector?.('[role="dialog"]')?.focus?.(); return; } const activeIndex = focusables.indexOf(root.activeElement); const nextIndex = event.shiftKey ? activeIndex <= 0 ? focusables.length - 1 : activeIndex - 1 : activeIndex === focusables.length - 1 ? 0 : activeIndex + 1; event.preventDefault?.(); focusables[nextIndex]?.focus?.(); }); boundDocuments.add(root); } const rendered = renderAppShell(demoState); ensureReportInterpretationProjection(); return rendered; }; if (globalThis.document) { if (globalThis.document.readyState === "loading") { globalThis.document.addEventListener( "DOMContentLoaded", () => initializePatientServiceDesk(), { once: true } ); } else { initializePatientServiceDesk(); } } })();