no message

This commit is contained in:
wangdongbo 2026-02-12 14:12:01 +08:00
parent 5d22b06b4b
commit 2363e17cc1
4 changed files with 185 additions and 149 deletions

View File

@ -384,7 +384,7 @@ $primary-color: #0877F1;
display: flex;
align-items: center;
padding: 12rpx 20rpx;
padding-bottom: env(safe-area-inset-bottom);
padding-bottom: 60rpx;
gap: 12rpx;
border-top: 1rpx solid #e0e0e0;
background: #fff;
@ -511,7 +511,7 @@ $primary-color: #0877F1;
background: #fff;
border-top: 1rpx solid #eee;
padding: 20rpx 0 20rpx 60rpx;
padding-bottom: env(safe-area-inset-bottom);
padding-bottom: 60rpx;
gap: 40rpx 50rpx;
flex-wrap: wrap;
background-color: #f5f5f5;
@ -541,7 +541,7 @@ $primary-color: #0877F1;
background-color: white;
border-top: 1rpx solid #e0e0e0;
padding: 16rpx;
margin-bottom: env(safe-area-inset-bottom);
margin-bottom: 60rpx;
display: flex;
align-items: center;
justify-content: space-between;
@ -686,7 +686,7 @@ $primary-color: #0877F1;
width: 100%;
max-height: 80vh;
padding: 20rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
padding-bottom: 80rpx;
position: relative;
box-sizing: border-box;
margin: 0;
@ -818,7 +818,7 @@ $primary-color: #0877F1;
background-color: white;
width: auto;
padding: 32rpx 20rpx 48rpx 20rpx;
padding-bottom: calc(48rpx + env(safe-area-inset-bottom));
padding-bottom: 108rpx;
text-align: center;
margin: 0 auto;
position: relative;

View File

@ -12,19 +12,6 @@
button.loading && button.loadingText ? button.loadingText : button.text
}}</text>
</view>
<!-- 病历类型选择弹窗 -->
<medical-case-type-selector
ref="typeSelectorRef"
@select="handleCaseTypeSelect"
/>
<!-- 进度显示弹窗 -->
<medical-case-progress
ref="progressRef"
@regenerate="handleRegenerateFromProgress"
@next="handleNextFromProgress"
/>
</view>
</template>
@ -32,8 +19,6 @@
import { ref, onMounted, onUnmounted } from "vue";
import request from "@/utils/http.js";
import api from "@/utils/api.js";
import MedicalCaseTypeSelector from "./medical-case-type-selector.vue";
import MedicalCaseProgress from "./medical-case-progress.vue";
const props = defineProps({
groupId: {
@ -56,11 +41,24 @@ const props = defineProps({
type: String,
default: "",
},
typeSelectorRef: {
type: Object,
default: null,
},
progressRef: {
type: Object,
default: null,
},
});
const emit = defineEmits(["streamText", "clearInput", "generatingStateChange"]);
const emit = defineEmits([
"streamText",
"clearInput",
"generatingStateChange",
"caseTypeSelect",
"regenerateFromProgress",
"nextFromProgress",
]);
const typeSelectorRef = ref(null);
const progressRef = ref(null);
const isGenerating = ref(false);
const buttons = ref([
@ -217,143 +215,22 @@ const handleAIAssistant = (button) => {
//
const handleSupplementRecord = (button) => {
typeSelectorRef.value?.open();
props.typeSelectorRef?.open();
};
//
const handleCaseTypeSelect = async (type) => {
try {
//
progressRef.value?.open(type.id);
progressRef.value?.updateProgress(10);
//
await requestWithStream({
url: "/getYoucanData/im",
data: {
type: "supplementMedicalCase",
groupId: props.groupId,
patientAccountId: props.patientAccountId || props.customerId,
corpId: props.corpId,
caseType: type.id,
},
onProgress: (data) => {
//
handleStreamData(data, type.id);
},
onComplete: (finalData) => {
//
handleComplete(finalData, type.id);
},
onError: (error) => {
progressRef.value?.close();
uni.showToast({
title: error.message || "生成病历失败",
icon: "none",
});
},
});
} catch (error) {
console.error("补充病历失败:", error);
progressRef.value?.close();
uni.showToast({
title: "操作失败,请重试",
icon: "none",
});
}
};
//
const requestWithStream = async ({
url,
data,
onProgress,
onComplete,
onError,
}) => {
try {
// loading false
const result = await request(
{
url,
data,
},
false
);
if (result.success && result.data) {
//
const extractedData = result.data.extractedData || {};
//
let progressValue = 20;
const fields = Object.entries(extractedData);
const delay = 300; //
for (let i = 0; i < fields.length; i++) {
const [key, value] = fields[i];
// ""
await new Promise((resolve) => setTimeout(resolve, delay));
onProgress({ key, value });
progressValue += Math.floor(60 / fields.length);
progressRef.value?.updateProgress(Math.min(progressValue, 80));
}
//
onComplete(result.data);
} else {
onError(new Error(result.message || "请求失败"));
}
} catch (error) {
onError(error);
}
};
//
const handleStreamData = (data, caseType) => {
const { key, value } = data;
//
progressRef.value?.addDetectedInfo(key, value);
};
//
const handleComplete = (finalData, caseType) => {
progressRef.value?.updateProgress(90);
progressRef.value?.setGenerating(true);
//
setTimeout(() => {
progressRef.value?.updateProgress(100);
progressRef.value?.setGenerating(false);
//
setTimeout(() => {
progressRef.value?.setCompleted(true, finalData);
}, 500);
}, 800);
emit("caseTypeSelect", type);
};
//
const handleRegenerateFromProgress = (data) => {
const type = { id: data.caseType };
handleCaseTypeSelect(type);
emit("regenerateFromProgress", data);
};
//
const handleNextFromProgress = (data) => {
//
const extractedData = data.data?.extractedData || {};
//
uni.navigateTo({
url: `/pages/case/ai-medical-case-form?caseType=${data.caseType}&patientId=${
props.patientId
}&groupId=${props.groupId}&formData=${encodeURIComponent(
JSON.stringify(extractedData)
)}`,
});
emit("nextFromProgress", data);
};
//

View File

@ -13,7 +13,7 @@
<view class="input-area">
<textarea v-if="!showVoiceInput" class="text-input" v-model="inputText" placeholder="我来说两句..."
@confirm="sendTextMessage" @focus="handleInputFocus" @input="handleInput"
:auto-height="true" :show-confirm-bar="false" :hold-keyboard="true"
:auto-height="true" :show-confirm-bar="false" :hold-keyboard="true"
ref="textareaRef"
/>
<input v-else class="voice-input-btn" :class="{ recording: isRecording }" @touchstart="startRecord"

View File

@ -165,12 +165,30 @@
:patientAccountId="chatInfo.userID || ''"
:patientId="patientId"
:corpId="corpId"
:typeSelectorRef="typeSelectorRef"
:progressRef="progressRef"
@streamText="handleStreamText"
@clearInput="handleClearInput"
@generatingStateChange="handleGeneratingStateChange"
@caseTypeSelect="handleCaseTypeSelect"
@regenerateFromProgress="handleRegenerateFromProgress"
@nextFromProgress="handleNextFromProgress"
/>
</template>
</ChatInput>
<!-- 病历类型选择弹窗 -->
<MedicalCaseTypeSelector
ref="typeSelectorRef"
@select="handleCaseTypeSelect"
/>
<!-- 进度显示弹窗 -->
<MedicalCaseProgress
ref="progressRef"
@regenerate="handleRegenerateFromProgress"
@next="handleNextFromProgress"
/>
</view>
</template>
@ -206,6 +224,9 @@ import SystemMessage from "./components/system-message.vue";
import ConsultAccept from "./components/consult-accept.vue";
import RejectReasonModal from "./components/reject-reason-modal.vue";
import AIAssistantButtons from "./components/ai-assistant-buttons.vue";
import MedicalCaseTypeSelector from "./components/medical-case-type-selector.vue";
import MedicalCaseProgress from "./components/medical-case-progress.vue";
import request from "@/utils/http.js";
const timChatManager = globalTimChatManager;
@ -283,6 +304,8 @@ const { initIMAfterLogin } = useAccountStore();
//
const chatInputRef = ref(null);
const aiAssistantRef = ref(null);
const typeSelectorRef = ref(null);
const progressRef = ref(null);
const isGenerating = ref(false);
const groupId = ref("");
@ -983,6 +1006,142 @@ const handleGeneratingStateChange = (generating) => {
isGenerating.value = generating;
};
//
const handleCaseTypeSelect = async (type) => {
try {
//
progressRef.value?.open(type.id);
progressRef.value?.updateProgress(10);
//
await requestWithStream({
url: "/getYoucanData/im",
data: {
type: "supplementMedicalCase",
groupId: groupId.value,
patientAccountId: chatInfo.value.userID || "",
corpId: corpId,
caseType: type.id,
},
onProgress: (data) => {
//
handleStreamData(data, type.id);
},
onComplete: (finalData) => {
//
handleComplete(finalData, type.id);
},
onError: (error) => {
progressRef.value?.close();
uni.showToast({
title: error.message || "生成病历失败",
icon: "none",
});
},
});
} catch (error) {
console.error("补充病历失败:", error);
progressRef.value?.close();
uni.showToast({
title: "操作失败,请重试",
icon: "none",
});
}
};
//
const requestWithStream = async ({
url,
data,
onProgress,
onComplete,
onError,
}) => {
try {
// loading false
const result = await request(
{
url,
data,
},
false
);
if (result.success && result.data) {
//
const extractedData = result.data.extractedData || {};
//
let progressValue = 20;
const fields = Object.entries(extractedData);
const delay = 300; //
for (let i = 0; i < fields.length; i++) {
const [key, value] = fields[i];
// ""
await new Promise((resolve) => setTimeout(resolve, delay));
onProgress({ key, value });
progressValue += Math.floor(60 / fields.length);
progressRef.value?.updateProgress(Math.min(progressValue, 80));
}
//
onComplete(result.data);
} else {
onError(new Error(result.message || "请求失败"));
}
} catch (error) {
onError(error);
}
};
//
const handleStreamData = (data, caseType) => {
const { key, value } = data;
//
progressRef.value?.addDetectedInfo(key, value);
};
//
const handleComplete = (finalData, caseType) => {
progressRef.value?.updateProgress(90);
progressRef.value?.setGenerating(true);
//
setTimeout(() => {
progressRef.value?.updateProgress(100);
progressRef.value?.setGenerating(false);
//
setTimeout(() => {
progressRef.value?.setCompleted(true, finalData);
}, 500);
}, 800);
};
//
const handleRegenerateFromProgress = (data) => {
const type = { id: data.caseType };
handleCaseTypeSelect(type);
};
//
const handleNextFromProgress = (data) => {
//
const extractedData = data.data?.extractedData || {};
//
uni.navigateTo({
url: `/pages/case/ai-medical-case-form?caseType=${data.caseType}&patientId=${
patientId.value
}&groupId=${groupId.value}&formData=${encodeURIComponent(
JSON.stringify(extractedData)
)}`,
});
};
//
defineExpose({
sendCommonPhrase,