feat: 联调对话功能
This commit is contained in:
+54
-35
@@ -1,18 +1,11 @@
|
||||
<template>
|
||||
<DiagnosisPage
|
||||
v-if="showDiagnosisPage"
|
||||
:case-item="caseItem"
|
||||
@open-settings="emit('open-settings')"
|
||||
@open-profile="openProfile"
|
||||
@go-home="emit('go-home')"
|
||||
/>
|
||||
<view v-else class="chat-page">
|
||||
<view class="chat-page">
|
||||
<view class="chat-shell">
|
||||
<view class="top-nav">
|
||||
<button class="icon-button" aria-label="设置" @click="emit('open-settings')">
|
||||
<button class="icon-button" aria-label="设置" @click="openSettings">
|
||||
<view class="settings-icon"></view>
|
||||
</button>
|
||||
<button class="icon-button home-button" aria-label="首页" @click="emit('go-home')">
|
||||
<button class="icon-button home-button" aria-label="首页" @click="goHome">
|
||||
<view class="home-icon"></view>
|
||||
</button>
|
||||
<view class="nav-spacer"></view>
|
||||
@@ -24,9 +17,9 @@
|
||||
<view class="case-header">
|
||||
<view class="case-title-row">
|
||||
<text class="case-heading">患者:{{ session.patient.name }} ({{ complaintShort }})</text>
|
||||
<button class="finish-button" @click="showDiagnosisPage = true">
|
||||
<button class="finish-button" :disabled="completingInquiry" @click="handleCompleteInquiry">
|
||||
<view class="check-icon"></view>
|
||||
<text>完成采集</text>
|
||||
<text>{{ completingInquiry ? '提交中' : '完成采集' }}</text>
|
||||
</button>
|
||||
</view>
|
||||
<view class="patient-meta">
|
||||
@@ -193,14 +186,19 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
|
||||
import type { ClinicalCase } from '../../api/cases'
|
||||
import { readStoredClinicalCase, type ClinicalCase } from '../../api/cases'
|
||||
import { createMockChatSession, sendMockChatMessage, type ChatMessage, type ChatSession } from '../../api/chat'
|
||||
import { createProfileOpener } from '../../api/navigation'
|
||||
import { streamSessionChat, streamSessionHint, type TrainingSession } from '../../api/session'
|
||||
import DiagnosisPage from '../diagnosis/diagnosis.vue'
|
||||
import { createHomeNavigator, createProfileOpener, createSettingsOpener } from '../../api/navigation'
|
||||
import {
|
||||
completeInquiry,
|
||||
readStoredTrainingScenario,
|
||||
streamSessionChat,
|
||||
streamSessionHint,
|
||||
updateStoredSessionStatus
|
||||
} from '../../api/session'
|
||||
|
||||
const props = defineProps<{
|
||||
caseItem: ClinicalCase | null
|
||||
caseItem?: ClinicalCase | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -210,6 +208,8 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const openProfile = createProfileOpener(emit)
|
||||
const openSettings = createSettingsOpener(emit)
|
||||
const goHome = createHomeNavigator(emit)
|
||||
|
||||
const session = reactive<ChatSession>({
|
||||
patient: {
|
||||
@@ -230,22 +230,19 @@ const session = reactive<ChatSession>({
|
||||
const draft = ref('')
|
||||
const sending = ref(false)
|
||||
const hinting = ref(false)
|
||||
const completingInquiry = ref(false)
|
||||
const scrollTop = ref(0)
|
||||
const toastMessage = ref('')
|
||||
const toastVisible = ref(false)
|
||||
const showDiagnosisPage = ref(false)
|
||||
const examPanelVisible = ref(false)
|
||||
const physicalPanelVisible = ref(false)
|
||||
const activeSessionId = ref<number | null>(null)
|
||||
const storedCase = ref<ClinicalCase | null>(null)
|
||||
|
||||
let toastTimer: ReturnType<typeof setTimeout> | null = null
|
||||
let activeStreamController: AbortController | null = null
|
||||
let activeHintController: AbortController | null = null
|
||||
|
||||
type StoredScenario = {
|
||||
session?: TrainingSession
|
||||
}
|
||||
|
||||
type AuxiliaryExam = {
|
||||
name: string
|
||||
result: string
|
||||
@@ -281,16 +278,18 @@ const physicalForm = reactive({
|
||||
otherFinding: ''
|
||||
})
|
||||
|
||||
const activeCase = computed(() => props.caseItem || storedCase.value)
|
||||
|
||||
const complaintShort = computed(() => {
|
||||
if (session.patient.chiefComplaint.includes('胸痛')) return '胸痛'
|
||||
return session.patient.chiefComplaint.slice(0, 6)
|
||||
})
|
||||
|
||||
function loadSession() {
|
||||
createMockChatSession(props.caseItem).then(result => {
|
||||
createMockChatSession(activeCase.value).then(result => {
|
||||
Object.assign(session.patient, result.patient)
|
||||
session.stages = result.stages
|
||||
const scenario = readStoredScenario()
|
||||
const scenario = readStoredTrainingScenario()
|
||||
if (scenario?.session?.session_id) {
|
||||
activeSessionId.value = scenario.session.session_id
|
||||
session.messages = scenario.session.patient_opening ? [
|
||||
@@ -311,17 +310,38 @@ function loadSession() {
|
||||
})
|
||||
}
|
||||
|
||||
function readStoredScenario() {
|
||||
const value = uni.getStorageSync('clinical-thinking-scenario')
|
||||
if (value && typeof value === 'object') return value as StoredScenario
|
||||
return null
|
||||
}
|
||||
|
||||
function sendQuickAction(content: string) {
|
||||
draft.value = content
|
||||
handleSend()
|
||||
}
|
||||
|
||||
async function handleCompleteInquiry() {
|
||||
if (completingInquiry.value) return
|
||||
if (sending.value || hinting.value) {
|
||||
showToast('请等待当前回复完成')
|
||||
return
|
||||
}
|
||||
|
||||
const sessionId = activeSessionId.value
|
||||
if (!sessionId) {
|
||||
showToast('未找到当前会话,请先生成模拟场景')
|
||||
return
|
||||
}
|
||||
|
||||
completingInquiry.value = true
|
||||
try {
|
||||
const result = await completeInquiry(sessionId)
|
||||
updateStoredSessionStatus(result.status)
|
||||
uni.navigateTo({
|
||||
url: '/pages/diagnosis/diagnosis'
|
||||
})
|
||||
} catch (error) {
|
||||
showToast(error instanceof Error ? error.message : '完成采集失败')
|
||||
} finally {
|
||||
completingInquiry.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function openExamPanel() {
|
||||
physicalPanelVisible.value = false
|
||||
examPanelVisible.value = true
|
||||
@@ -550,16 +570,15 @@ function showToast(message: string) {
|
||||
if (toastTimer) clearTimeout(toastTimer)
|
||||
toastMessage.value = message
|
||||
toastVisible.value = true
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
toastTimer = setTimeout(() => {
|
||||
toastVisible.value = false
|
||||
}, 2200)
|
||||
}
|
||||
|
||||
onMounted(loadSession)
|
||||
onMounted(() => {
|
||||
storedCase.value = readStoredClinicalCase()
|
||||
loadSession()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
activeStreamController?.abort()
|
||||
|
||||
Reference in New Issue
Block a user