This commit is contained in:
Your Name
2026-04-17 12:00:54 +08:00
parent d5fa4dd73c
commit a5d2baf731
6 changed files with 111 additions and 63 deletions
+1 -1
View File
@@ -221,7 +221,7 @@ export function generateOrderQrcode(params: any) {
// ========== IM / 企业微信聊天记录 ==========
/** 腾讯云 IM 单聊漫游消息(诊单维度:患者 patient_* 与医生 doctor_* */
export function getImChatMessages(params: { diagnosis_id: number }) {
export function getImChatMessages(params: { diagnosis_id: number; only_archived?: 0 | 1 }) {
return request.get({ url: '/tcm.diagnosis/getImChatMessages', params })
}
@@ -1448,6 +1448,7 @@ const createOrderRules: FormRules = {
patient_id: [{ required: true, message: '请选择诊单患者', trigger: 'change' }],
recipient_name: [{ required: true, message: '请输入收货人', trigger: 'blur' }],
recipient_phone: [{ required: true, message: '请输入收货手机', trigger: 'blur' }],
region: [{ required: true, message: '请选择省/市/区', trigger: 'change', type: 'array' }],
shipping_address: [{ required: true, message: '请输入收货地址', trigger: 'blur' }],
fee_type: [{ required: true, message: '请选择费用类别', trigger: 'change' }],
amount: [
@@ -2243,6 +2243,7 @@ async function loadEditPaidOrders(diagnosisId: number, prescriptionOrderId?: num
const editRules: FormRules = {
recipient_name: [{ required: true, message: '请输入收货人', trigger: 'blur' }],
recipient_phone: [{ required: true, message: '请输入手机', trigger: 'blur' }],
region: [{ required: true, message: '请选择省/市/区', trigger: 'change', type: 'array' }],
shipping_address: [{ required: true, message: '请输入地址', trigger: 'blur' }],
fee_type: [{ required: true, message: '请选择费用类别', trigger: 'change' }],
amount: [
@@ -9,9 +9,9 @@
</el-alert>
<div class="toolbar mb-3">
<el-button type="primary" link :loading="loading" @click="load">
<el-button type="primary" link :loading="loading" @click="refreshLive">
<el-icon class="mr-1"><Refresh /></el-icon>
刷新
刷新同步云端最新
</el-button>
</div>
@@ -19,44 +19,42 @@
<template v-if="!loading && rows.length">
<div class="chat-list">
<div
v-for="row in rows"
:key="row.msg_id"
v-for="item in rows"
:key="item.raw.msg_id"
class="chat-row"
:class="row.is_from_doctor ? 'from-doctor' : 'from-patient'"
:class="item.raw.is_from_doctor ? 'from-doctor' : 'from-patient'"
>
<div class="meta">
<span class="name">{{ senderLabel(row) }}</span>
<span class="time">{{ formatTime(row.time) }}</span>
<el-tag v-if="typeLabel(row)" size="small" type="info" class="ml-2">
{{ typeLabel(row) }}
<span class="name">{{ senderLabel(item.raw) }}</span>
<span class="time">{{ formatTime(item.raw.time) }}</span>
<el-tag v-if="item.tag" size="small" type="info" class="ml-2">
{{ item.tag }}
</el-tag>
</div>
<div class="bubble">
<template v-if="row.msg_type === 'image' && row.image_url">
<template v-if="item.raw.msg_type === 'image' && item.raw.image_url">
<el-image
:src="row.image_url"
:preview-src-list="[row.image_url]"
:src="item.raw.image_url"
:preview-src-list="[item.raw.image_url]"
fit="contain"
class="chat-img"
/>
</template>
<template v-else-if="(row.msg_type === 'file' || row.msg_type === 'sound' || row.msg_type === 'video') && row.file_url">
<el-link :href="row.file_url" target="_blank" type="primary">
{{ row.file_name || '打开文件' }}
<template v-else-if="(item.raw.msg_type === 'file' || item.raw.msg_type === 'sound' || item.raw.msg_type === 'video') && item.raw.file_url">
<el-link :href="item.raw.file_url" target="_blank" type="primary">
{{ item.raw.file_name || '打开文件' }}
</el-link>
</template>
<template v-else>
<template v-for="fr in [parseImFriendly(row)]" :key="row.msg_id + '-body'">
<div v-if="fr" class="friendly-text">
<div class="friendly-main">{{ fr.main }}</div>
<div v-if="fr.sub" class="friendly-sub">{{ fr.sub }}</div>
</div>
<div v-else-if="row.msg_type === 'text' && row.text" class="text-content">
{{ row.text }}
</div>
<div v-else-if="row.text" class="text-content">{{ row.text }}</div>
<span v-else class="muted">无法展示该消息类型</span>
</template>
<div v-if="item.friendly" class="friendly-text">
<div class="friendly-main">{{ item.friendly.main }}</div>
<div v-if="item.friendly.sub" class="friendly-sub">{{ item.friendly.sub }}</div>
</div>
<div v-else-if="item.raw.msg_type === 'text' && item.raw.text" class="text-content">
{{ item.raw.text }}
</div>
<div v-else-if="item.raw.text" class="text-content">{{ item.raw.text }}</div>
<span v-else class="muted">无法展示该消息类型</span>
</template>
</div>
</div>
@@ -80,12 +78,43 @@ const props = defineProps<{
}>()
const loading = ref(false)
const rows = shallowRef<any[]>([])
const rawRows = shallowRef<any[]>([])
const patientImId = ref('')
const patientName = ref('')
const patientImHint = computed(() => patientImId.value || 'patient_*')
interface EnrichedRow {
raw: any
friendly: FriendlyParse | null
tag: string
}
const MSG_TYPE_LABELS: Record<string, string> = {
text: '',
image: '图片',
file: '文件',
sound: '语音',
video: '视频',
location: '位置',
custom: '自定义',
face: '表情',
other: ''
}
const rows = computed<EnrichedRow[]>(() =>
rawRows.value.map((row) => {
const fr = parseImFriendly(row)
let tag = ''
if (fr?.tag) {
tag = fr.tag
} else {
tag = MSG_TYPE_LABELS[row.msg_type] || (row.msg_type !== 'other' ? row.msg_type : '')
}
return { raw: row, friendly: fr, tag }
})
)
function formatTime(ts: number | undefined) {
if (ts == null || !ts) return '—'
const sec = ts > 1e12 ? Math.floor(ts / 1000) : ts
@@ -103,23 +132,6 @@ function parseImFriendly(row: any): FriendlyParse | null {
return null
}
function typeLabel(row: any) {
const fr = parseImFriendly(row)
if (fr?.tag) return fr.tag
const m: Record<string, string> = {
text: '',
image: '图片',
file: '文件',
sound: '语音',
video: '视频',
location: '位置',
custom: '自定义',
face: '表情',
other: ''
}
return m[row.msg_type] || (row.msg_type !== 'other' ? row.msg_type : '')
}
function senderLabel(row: any) {
if (row.is_from_doctor) {
return row.from_staff_name ? `医生(${row.from_staff_name}` : '医生/员工'
@@ -127,35 +139,42 @@ function senderLabel(row: any) {
return patientName.value ? `患者(${patientName.value}` : '患者'
}
async function load() {
async function load(onlyArchived = false) {
if (!props.diagnosisId) return
loading.value = true
try {
const res = (await getImChatMessages({ diagnosis_id: props.diagnosisId })) as {
const res = (await getImChatMessages({
diagnosis_id: props.diagnosisId,
only_archived: onlyArchived ? 1 : 0
})) as {
lists?: any[]
patient_im_id?: string
patient_name?: string
}
rows.value = res?.lists || []
rawRows.value = res?.lists || []
patientImId.value = res?.patient_im_id || ''
patientName.value = res?.patient_name || ''
} catch (e) {
console.error(e)
rows.value = []
rawRows.value = []
} finally {
loading.value = false
}
}
function refreshLive() {
load(false)
}
watch(
() => props.diagnosisId,
() => {
load()
load(true)
},
{ immediate: true }
)
defineExpose({ refresh: load })
defineExpose({ refresh: refreshLive })
</script>
<style scoped lang="scss">