hn-hlw-app/components/custom-message/consult-message-custom.vue

191 lines
4.3 KiB
Vue
Raw Normal View History

2026-07-27 11:26:39 +08:00
<template>
<view v-if="shouldRender">
<pass-rx-card v-if="payload && payload.data === 'AUDIPASS'" :extension="payload.extension" />
<view
v-else-if="isVideoConsult && videoConsultDisplayText"
class="chat-row"
:class="[messageFlow === 'out' ? 'chat-row--end' : '']"
>
<image
:src="avatarSrc"
class="chat-avatar chat-avatar--square"
:class="[messageFlow === 'out' ? 'chat-avatar--right' : '']"
/>
<view class="chat-row-content">
<view
class="video-record-bubble"
:class="[messageFlow === 'out' ? 'my-message' : '']"
>
<image class="video-record-icon" :src="videoIconSrc" mode="aspectFit" />
<text class="video-record-text">{{ videoConsultDisplayText }}</text>
</view>
</view>
</view>
<view
v-else-if="showSystemTip"
class="message-item"
>
系统提示{{ payload.extension }}
</view>
</view>
</template>
<script setup>
import { computed } from "vue";
import PassRxCard from "./rx-pass-card.vue";
// messageItem.payload data: 消息类型 startChat 会话开始 , endChat 会话结束 ,
const props = defineProps({
messageItem: {
type: Object,
default: () => ({}),
},
partnerAvatar: {
type: String,
default: "",
},
});
const payload = computed(() => {
return props.messageItem.payload;
});
const messageFlow = computed(() => {
return props.messageItem && typeof props.messageItem.flow === "string"
? props.messageItem.flow
: "";
});
const isVideoConsult = computed(() => {
return !!(payload.value && payload.value.description === "VIDEO_CONSULT");
});
function parseVideoRecordExtension(ext) {
if (!ext || typeof ext !== "string") return null;
try {
const obj = JSON.parse(ext);
if (!obj || typeof obj !== "object") return null;
if (!obj.doctorText || !obj.patientText) return null;
return obj;
} catch (e) {
return null;
}
}
const videoConsultDisplayText = computed(() => {
const pl = payload.value || {};
const ext = typeof pl.extension === "string" ? pl.extension.trim() : "";
if (!ext) return "";
const record = parseVideoRecordExtension(ext);
if (!record) {
// 兼容历史extension 直接是文案
return ext;
}
// 同一条消息在医生端/患者端展示不同文案:发送方(out)=doctorText接收方(in)=patientText
return messageFlow.value === "in" ? record.patientText : record.doctorText;
});
const showSystemTip = computed(() => {
const pl = payload.value || {};
return !!(
pl.extension &&
pl.data !== "ACCEPTCONSULT" &&
pl.data !== "REPEATMEDICALADVICE"
);
});
const shouldRender = computed(() => {
const pl = payload.value || {};
return (
(pl && pl.data === "AUDIPASS") ||
(isVideoConsult.value && !!videoConsultDisplayText.value) ||
showSystemTip.value
);
});
const avatarSrc = computed(() => {
const msg = props.messageItem || {};
if (messageFlow.value === "in" && props.partnerAvatar) return props.partnerAvatar;
return (
msg.avatar ||
(msg.payload && msg.payload.avatar) ||
"https://web.sdk.qcloud.com/component/TUIKit/assets/avatar_21.png"
);
});
const videoIconSrc = "/static/icons/video-consult.svg";
</script>
<style scoped lang="scss">
//灰色 字体颜色
.message-item {
padding: 10px;
color: #666;
// border-radius: 10px;
margin: 0px 0 10px 0;
text-align: center;
font-size: 14px;
}
/* Align with existing chat bubble layout (see pages/chat/chat-message.vue) */
.chat-row {
display: flex;
padding-bottom: 10px;
width: 100%;
}
.chat-row--end {
justify-content: flex-end;
}
.chat-row-content {
max-width: 80%;
margin: 0 10px;
overflow: hidden;
order: 2;
}
.chat-avatar {
flex-shrink: 0;
width: 36px;
height: 36px;
order: 1;
}
.chat-avatar--right {
order: 3;
}
.chat-avatar--square {
border-radius: 4px;
}
.video-record-bubble {
display: inline-flex;
align-items: center;
max-width: 100%;
padding: 10px 12px;
background: #f2f2f2;
color: #333;
border-radius: 6px;
font-size: 14px;
line-height: 1.2;
}
.video-record-bubble.my-message {
background: #dceafd;
}
.video-record-icon {
width: 16px;
height: 16px;
flex: 0 0 auto;
}
.video-record-text {
margin-left: 6px;
white-space: normal;
word-break: break-word;
overflow: visible;
}
</style>