fix: 在线复诊

This commit is contained in:
2025-12-23 11:05:12 +08:00
parent f2d7317982
commit e9b79b2963
23 changed files with 2526 additions and 254 deletions

View File

@@ -1,7 +1,8 @@
<script setup>
import { ref, provide, nextTick, onMounted, onUnmounted } from 'vue';
import { ref, provide, nextTick, onMounted, onUnmounted, computed } from 'vue';
import { message } from 'ant-design-vue';
import { message, Modal } from 'ant-design-vue';
import { PlusOutlined, CloseOutlined } from '@ant-design/icons-vue';
import { useFileUpload } from '../composables/useFileUpload.ts';
import { useRecording } from '../composables/useRecording.ts';
@@ -9,9 +10,13 @@ import { useChatStore } from '../stores/chat.ts';
import { useThemeStore } from '../stores/theme.ts';
import { useUserStore } from '../stores/user.ts';
import { sendMessage } from '../utils/request.ts';
import { usePrescriptionStore } from '#/store/prescription';
import { getProductListDoctorReception } from '#/views/doctor/doctor-reception/api';
import { endConsultation } from '#/views/doctor/online-consultation/api/index';
import CustomTextarea from './CustomTextarea.vue';
import EmojiPicker from './EmojiPicker.vue';
import FileUploadPreview from './FileUploadPreview.vue';
import QuickReplyBubbles from '#/views/doctor/online-consultation/components/QuickReplyBubbles.vue';
// 定义 props
const props = defineProps({
@@ -24,6 +29,7 @@ const props = defineProps({
const userStore = useUserStore();
const chatStore = useChatStore();
const themeStore = useThemeStore();
const prescriptionStore = usePrescriptionStore();
const messageText = ref('');
const messageInputRef = ref(null);
@@ -46,21 +52,36 @@ const { isRecording, startRecording, stopRecording } = useRecording();
const sendUploadedFile = () => {
if (!uploadPreview.value) return;
// 消息类型映射
const messageTypeMap = {
text: 0,
image: 1,
audio: 2,
video: 3,
prescription: 4,
'medical-record': 5,
'video-call': 6,
'audio-call': 7,
file: 8,
};
const messageObj = {
type: uploadPreview.value.type,
content: uploadPreview.value.url,
time: new Date().toLocaleTimeString().slice(0, 5),
senderId: `${userStore.currentUser.id}`,
receiverId: chatStore.currentFriend.id,
message_type: messageTypeMap[uploadPreview.value.type] || 0,
message_content: uploadPreview.value.url,
created_at_text: new Date().toLocaleTimeString().slice(0, 5),
created_at: Date.now(),
sender_user_id: `doctor-${userStore.currentUser.doctor_id}`,
receiver_user_id: chatStore.currentFriend.id,
room_id: chatStore.currentFriend.room_id,
read: true,
duration: 0,
};
chatStore.addMessage(messageObj, userStore.currentUser.id);
chatStore.addMessage(messageObj, userStore.currentUser.doctor_id);
// 发送到服务器
sendMessage({
senderId: userStore.currentUser.id,
senderId: userStore.currentUser.doctor_id,
receiverId: chatStore.currentFriend.id,
type: uploadPreview.value.type,
content: uploadPreview.value.url,
@@ -92,26 +113,45 @@ const sendTextMessage = async () => {
uploadPreview.value = null;
}
// 创建消息对象
// 消息类型映射
const messageTypeMap = {
text: 0,
image: 1,
audio: 2,
video: 3,
prescription: 4,
'medical-record': 5,
'video-call': 6,
'audio-call': 7,
file: 8,
register: 10,
'patient-experience': 11,
'product-card': 12,
'end-consultation': 13,
};
// 创建消息对象 - 使用数据库字段名
const messageObj = {
type: messageType,
content: messageContent,
time: new Date().toLocaleTimeString().slice(0, 5),
senderId: `${userStore.currentUser.id}`,
receiverId: chatStore.currentFriend.id,
message_type: messageTypeMap[messageType] || 0,
message_content: messageContent,
created_at_text: new Date().toLocaleTimeString().slice(0, 5),
created_at: Date.now(),
sender_user_id: `doctor-${userStore.currentUser.doctor_id}`,
receiver_user_id: chatStore.currentFriend.id,
room_id: chatStore.currentFriend.room_id,
isSent: true,
read: true,
duration: 0,
};
// return console.log('发送消息:' + userStore.currentUser.id, messageObj);
// return console.log('发送消息:' + userStore.currentUser.doctor_id, messageObj);
// 添加到本地消息列表
chatStore.addMessage(messageObj, userStore.currentUser.id);
chatStore.addMessage(messageObj, userStore.currentUser.doctor_id);
// 发送到服务器
try {
await sendMessage({
senderId: userStore.currentUser.id,
senderId: userStore.currentUser.doctor_id,
receiverId: chatStore.currentFriend.id,
roomId: chatStore.currentFriend.room_id,
type: messageType,
@@ -208,21 +248,23 @@ const handleAudioRecorded = (event) => {
const { url, duration } = event.detail;
const messageObj = {
type: 'audio',
content: url,
time: new Date().toLocaleTimeString().slice(0, 5),
senderId: `${userStore.currentUser.id}`,
receiverId: chatStore.currentFriend.id,
message_type: 2, // audio
message_content: url,
created_at_text: new Date().toLocaleTimeString().slice(0, 5),
created_at: Date.now(),
sender_user_id: `doctor-${userStore.currentUser.doctor_id}`,
receiver_user_id: chatStore.currentFriend.id,
room_id: chatStore.currentFriend.room_id,
isSent: true,
read: true,
duration,
};
chatStore.addMessage(messageObj, userStore.currentUser.id);
chatStore.addMessage(messageObj, userStore.currentUser.doctor_id);
// 发送到服务器
sendMessage({
senderId: userStore.currentUser.id,
senderId: userStore.currentUser.doctor_id,
receiverId: chatStore.currentFriend.id,
roomId: chatStore.currentFriend.room_id,
isSent: true,
@@ -262,7 +304,6 @@ const emit = defineEmits([
// 开方功能触发函数
const handleOpenPrescription = () => {
// 获取当前会话的register_id,这里假设可以通过某种方式获取
console.log(chatStore.currentFriend.register_id, 'sssssssssssssss')
// 例如从聊天存储或props中获取
const registerId = chatStore.currentFriend?.register_id || 66;
@@ -275,10 +316,160 @@ const handleOpenPrescription = () => {
}
};
// 处理快速回复选择
const handleQuickReplySelect = (content) => {
// 设置输入框内容并发送
messageText.value = content;
sendTextMessage();
};
// 判断是否显示在线复诊相关按钮
const showOnlineConsultationButtons = computed(() => {
// 检查是否有 register_id,如果有则说明是在线复诊场景
return !!chatStore.currentFriend?.register_id;
});
// 将患者就诊经历中的药品加入处方单
const handleAddPatientProductsToPrescription = async () => {
// 检查处方store是否已初始化
if (!prescriptionStore.currentRegisterId) {
const registerId = chatStore.currentFriend?.register_id;
if (registerId) {
prescriptionStore.initializePrescription(registerId, false);
} else {
message.warning('请先接诊患者');
return;
}
}
// 从聊天记录中筛选出所有 message_type=11 的消息(患者就诊经历)
const experienceMessages = chatStore.messages.filter(
(msg) => msg.message_type === 11
);
if (experienceMessages.length === 0) {
message.warning('当前聊天没有可添加的药品');
return;
}
// 获取诊所ID
let storeId = prescriptionStore.myStoreId;
if (!storeId || storeId === 0) {
if (prescriptionStore.myStoreList && prescriptionStore.myStoreList.length > 0) {
storeId = prescriptionStore.myStoreList[0].id;
} else {
message.warning('请先选择诊所');
return;
}
}
// 按时间排序,取最新的就诊经历
const sortedMessages = [...experienceMessages].sort((a, b) => {
const timeA = a.created_at ? new Date(a.created_at).getTime() : (a.timestamp || 0);
const timeB = b.created_at ? new Date(b.created_at).getTime() : (b.timestamp || 0);
return timeB - timeA; // 降序排列,最新的在前
});
const latestMessage = sortedMessages[0];
try {
// 解析最新消息的内容
let experienceData;
try {
experienceData = typeof latestMessage.message_content === 'string'
? JSON.parse(latestMessage.message_content)
: latestMessage.message_content;
} catch (e) {
console.error('解析就诊经历消息失败:', e);
message.warning('当前聊天没有可添加的药品');
return;
}
// 获取药品名称
const drugName = experienceData.drug_name;
if (!drugName) {
message.warning('当前聊天没有可添加的药品');
return;
}
// 通过药品名称搜索药品
const res = await getProductListDoctorReception({
store_id: storeId,
type: 2, // 中成(西)药
name: drugName,
});
if (!res || res.length === 0) {
message.warning('当前聊天没有可添加的药品');
return;
}
// 使用第一个匹配的药品
const drugData = res[0];
// 检查药品是否已在处方中
const existItem = prescriptionStore.currentDrugs.find(
(item) => item.index_id === drugData.id,
);
if (existItem) {
message.warning('该药品已在处方中');
return;
}
// 添加药品到处方单
const success = prescriptionStore.addProducts(drugData);
if (success) {
message.success(`已将${drugData.drug.drug_name}添加到处方单`);
// 触发打开处方模态框事件
emit('openPrescription', prescriptionStore.currentRegisterId || chatStore.currentFriend?.register_id);
}
} catch (error) {
console.error('添加药品失败:', error);
message.error('添加药品失败,请重试');
}
};
// 结束问诊
const handleEndConsultation = () => {
const registerId = chatStore.currentFriend?.register_id;
if (!registerId) {
message.warning('患者信息不完整,无法结束接诊');
return;
}
const patientName = chatStore.currentFriend?.nick_name || '患者';
Modal.confirm({
title: '确认结束接诊',
content: `确定要结束${patientName}的复诊吗?`,
okText: '确定',
cancelText: '取消',
onOk: async () => {
try {
await endConsultation({
register_id: registerId,
doctor_id: userStore.currentUser?.doctor_id || '39',
reason: '医生主动结束'
});
message.success('结束接诊成功');
} catch (error) {
console.error('结束接诊失败:', error);
message.error('结束接诊失败,请重试');
}
}
});
};
</script>
<template>
<div class="message-input-container" :class="{ dark: themeStore.isDarkMode }">
<div class="message-input-container flex-shrink-0 bg-white dark:bg-gray-800 border-t border-gray-200 dark:border-gray-700">
<!-- 快速回复气泡(仅在线复诊场景显示) -->
<QuickReplyBubbles
v-if="chatStore.currentFriend"
:doctor-id="'32'"
@select-reply="handleQuickReplySelect"
/>
<!-- 文件上传预览 -->
<FileUploadPreview v-if="uploadPreview" />
@@ -328,6 +519,24 @@ const handleOpenPrescription = () => {
>
<i class="fas fa-microphone"></i>
</button>
<!-- 添加药品按钮(仅在线复诊场景显示) -->
<button
v-if="showOnlineConsultationButtons"
class="function-btn"
title="将患者就诊经历中的药品加入处方单"
@click="handleAddPatientProductsToPrescription"
>
<PlusOutlined />
</button>
<!-- 结束问诊按钮(仅在线复诊场景显示) -->
<button
v-if="showOnlineConsultationButtons"
class="function-btn end-consultation-btn"
title="结束问诊"
@click="handleEndConsultation"
>
<CloseOutlined />
</button>
</div>
<div class="input-container">
@@ -378,14 +587,12 @@ const handleOpenPrescription = () => {
<style scoped>
.message-input-container {
padding: 20px;
border-top: 1px solid #e2e8f0;
background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
position: relative;
background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
}
.message-input-container.dark {
border-top-color: #374151;
background: linear-gradient(135deg, #2d2d2d 0%, #1f2937 100%);
.dark .message-input-container {
background: linear-gradient(135deg, #1f2937 0%, #111827 100%);
}
.input-container {
@@ -398,7 +605,11 @@ const handleOpenPrescription = () => {
display: flex;
align-items: center;
padding: 8px;
border-top: 1px solid #666666;
border-top: 1px solid #e2e8f0;
}
.dark .toolbar {
border-top-color: #374151;
}
.function-btn {
@@ -413,10 +624,18 @@ const handleOpenPrescription = () => {
color: #666;
}
.dark .function-btn {
color: #9ca3af;
}
.function-btn:hover {
background-color: #f0f0f0;
}
.dark .function-btn:hover {
background-color: #374151;
}
.prescription-button {
color: #455cda;
font-weight: 500;
@@ -426,6 +645,21 @@ const handleOpenPrescription = () => {
background-color: #e6e9ff;
}
.end-consultation-btn {
color: #ff4d4f;
font-weight: 500;
}
.end-consultation-btn:hover {
background-color: #fff1f0;
color: #ff4d4f;
}
.dark .end-consultation-btn:hover {
background-color: rgba(255, 77, 79, 0.2);
color: #ff4d4f;
}
.function-buttons {
display: flex;
gap: 12px;
@@ -521,12 +755,12 @@ const handleOpenPrescription = () => {
height: 100px;
}
.message-input-container.dark .function-btn {
.dark .function-btn {
background: linear-gradient(135deg, #374151, #4b5563);
color: #9ca3af;
}
.message-input-container.dark .function-btn:hover {
.dark .function-btn:hover {
background: linear-gradient(135deg, #4361ee, #3f37c9);
color: white;
}