feat: 联调对话功能

This commit is contained in:
王天骄
2026-06-09 17:00:23 +08:00
parent 3414d0662c
commit 2192b855a1
77 changed files with 1082 additions and 487 deletions
+60 -35
View File
@@ -1,17 +1,11 @@
<template>
<AssessmentPage
v-if="showAssessmentPage"
@open-settings="emit('open-settings')"
@open-profile="openProfile"
@go-home="emit('go-home')"
/>
<view v-else class="treatment-page">
<view class="treatment-page">
<view class="treatment-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>
@@ -21,12 +15,12 @@
</view>
<view class="case-header">
<text class="case-heading">患者陈先生 (胸痛)</text>
<text class="case-heading">患者{{ patientName }} ({{ complaintShort }})</text>
<view class="patient-meta">
<text>姓名陈先生</text>
<text>性别</text>
<text>年龄60</text>
<text>科室心血管内科</text>
<text>姓名{{ patientName }}</text>
<text>性别{{ patientGender }}</text>
<text>年龄{{ patientAge }}</text>
<text>科室{{ patientDepartment }}</text>
</view>
</view>
@@ -75,7 +69,7 @@
class="treatment-input"
v-model="form.principle"
type="text"
placeholder="请输入初步诊断..."
placeholder="请输入治疗原则..."
placeholder-class="input-placeholder"
/>
</view>
@@ -131,13 +125,14 @@
</template>
<script setup lang="ts">
import { computed, onUnmounted, reactive, ref } from 'vue'
import type { ClinicalCase } from '../../api/cases'
import { createProfileOpener } from '../../api/navigation'
import AssessmentPage from '../assessment/assessment.vue'
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
import { readStoredClinicalCase, type ClinicalCase } from '../../api/cases'
import { createHomeNavigator, createProfileOpener, createSettingsOpener } from '../../api/navigation'
import { readActiveSessionId } from '../../api/session'
import { submitTreatment, type TreatmentDraft } from '../../api/treatment'
defineProps<{
caseItem: ClinicalCase | null
const props = defineProps<{
caseItem?: ClinicalCase | null
}>()
const emit = defineEmits<{
@@ -147,6 +142,8 @@ const emit = defineEmits<{
}>()
const openProfile = createProfileOpener(emit)
const openSettings = createSettingsOpener(emit)
const goHome = createHomeNavigator(emit)
const form = reactive({
principle: '',
@@ -156,45 +153,71 @@ const form = reactive({
const submitting = ref(false)
const submitted = ref(false)
const showAssessmentPage = ref(false)
const toastMessage = ref('')
const toastVisible = ref(false)
const storedCase = ref<ClinicalCase | null>(null)
let toastTimer: ReturnType<typeof setTimeout> | null = null
const activeCase = computed(() => props.caseItem || storedCase.value)
const patientName = computed(() => activeCase.value?.patientName || '陈先生')
const patientGender = computed(() => activeCase.value?.gender || '男')
const patientAge = computed(() => activeCase.value?.age || 60)
const patientDepartment = computed(() => activeCase.value?.department || '心血管内科')
const complaintShort = computed(() => {
const title = activeCase.value?.title || '持续胸痛3小时'
return title.includes('胸痛') ? '胸痛' : title.slice(0, 6)
})
const buttonText = computed(() => {
if (submitting.value) return '提交中...'
if (submitted.value) return '已提交'
return '下一步'
})
function handleNext() {
async function handleNext() {
if (submitting.value) return
submitting.value = true
uni.setStorageSync('clinical-thinking-treatment', {
...form,
measures: form.measures.filter(item => item.trim()),
submittedAt: new Date().toISOString()
})
setTimeout(() => {
try {
const sessionId = readActiveSessionId()
const orders = form.orders.trim()
const draft: TreatmentDraft = {
treatmentPrinciple: form.principle,
treatmentMeasures: form.measures.map(item => item.trim()).filter(Boolean).join(''),
riskPlan: orders,
communication: orders,
followUp: orders
}
const result = await submitTreatment(sessionId, draft)
uni.setStorageSync('clinical-thinking-treatment', result)
submitted.value = true
uni.redirectTo({
url: '/pages/assessment/assessment',
fail() {
submitted.value = false
showToast('进入评价页失败,请重试')
}
})
} catch (error) {
showToast(error instanceof Error ? error.message : '治疗方案提交失败')
} finally {
submitting.value = false
showAssessmentPage.value = true
}, 600)
}
}
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(() => {
storedCase.value = readStoredClinicalCase()
})
onUnmounted(() => {
if (toastTimer) clearTimeout(toastTimer)
})
@@ -235,6 +258,7 @@ page {
min-height: 884px;
background: #f9f9ff;
overflow-x: hidden;
overflow-y: auto;
}
.top-nav {
@@ -355,6 +379,7 @@ page {
.stepper {
position: relative;
padding: 8px 0;
display: flex;
align-items: center;