feat(emergency): 急救宣教推送改为后端推 article 卡片

前端不再通过 postMessage 推送自定义消息,改由后端 push/send
接口直接推送 businessID=article 的自定义消息到 IM 会话。iweb
端新增 article 卡片渲染分支(左缩略图 + 右标题摘要横向布局,
max-width 280px),并加消息接收调试日志。

同时切换开发环境后台地址到 10.10.10.228:19996。
This commit is contained in:
wanghao
2026-07-07 17:40:50 +08:00
parent 48eaec6393
commit 5d7df50e25
12 changed files with 26503 additions and 41 deletions
+2 -2
View File
@@ -11,13 +11,13 @@ VITE_PUBLIC_PATH = /
VITE_DROP_CONSOLE = false
#后台接口父地址(必填)
VITE_GLOB_API_URL=http://10.10.20.18
VITE_GLOB_API_URL=http://10.10.10.228:19996
#VITE_GLOB_API_URL=https://xj-api.mcrm.vip:8888
#VITE_GLOB_API_URL=http://192.168.1.223
#VITE_GLOB_API_URL=http://cqyt.test.yg.dt.io
#后台接口全路径地址(必填)
VITE_GLOB_DOMAIN_URL=http://10.10.20.18
VITE_GLOB_DOMAIN_URL=http://10.10.10.228:19996
#VITE_GLOB_DOMAIN_URL=https://xj-api.mcrm.vip:8888
#VITE_GLOB_DOMAIN_URL=http://192.168.1.223
#VITE_GLOB_DOMAIN_URL=http://cqyt.test.yg.dt.io
@@ -94,6 +94,15 @@
</div>
</div>
</template>
<template v-else-if="isCustom.businessID === constant.typeArticle">
<div class="article-card">
<img v-if="isCustom?.messageImageUrl" :src="isCustom?.messageImageUrl" class="article-cover" />
<div class="article-info">
<div class="article-title">{{ isCustom?.title }}</div>
<div v-if="isCustom?.content" class="article-content">{{ isCustom?.content }}</div>
</div>
</div>
</template>
<template v-else-if="isCustom.businessID === constant.typeBusinessCard">
<div style="cursor: pointer; min-width: 180px">
<div class="business-type">
@@ -372,6 +381,56 @@
}
}
.article-card {
display: flex;
align-items: center;
gap: 8px;
max-width: 280px;
padding: 8px;
border-radius: 8px;
background: #f7f7f7;
border: 1px solid #ececec;
.article-cover {
width: 60px;
height: 60px;
border-radius: 6px;
flex-shrink: 0;
object-fit: cover;
}
.article-info {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 4px;
}
.article-title {
font-size: 14px;
font-weight: 500;
color: #333;
line-height: 1.3;
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.article-content {
font-size: 12px;
color: #7d7d7d;
line-height: 1.3;
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
}
.img-list {
img {
width: 100px;
@@ -115,6 +115,14 @@ export default class TUIChatServer extends IComponentServer {
}
private handleMessageReceived(event: any) {
// 调试日志:打印收到的所有消息,看后端推送的是什么格式
console.log('[IM 收到消息]', event?.data?.map((m: any) => ({
type: m?.type,
text: m?.payload?.text,
data: m?.payload?.data,
description: m?.payload?.description,
extension: m?.payload?.extension,
})));
event?.data?.forEach((message: Message) => {
if (message?.conversationID === this?.store?.conversation?.conversationID) {
this.currentStore.messageList = [...this.currentStore.messageList, message];
@@ -31,6 +31,7 @@ const constant: any = {
typeIphone: 'iphone',
typeMini: 'miniprogram',
typeSystem: 'system',
typeArticle: 'article',
typeBusinessCard: 'business_card',
typeArchives: 'archives',
typeMedicalExaminationReport: 'medical_examination_report',
+26425
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"><link rel="icon" href="faviconnew.png"><title>即时通信</title><link href="css/vendors~app.3f294141.css" rel="stylesheet"><link href="css/app.e6e597ee.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but 腾讯云即时通信 Web-IM doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="./TCaptcha.js"></script><script src="./aegis.min.js"></script><script>/**
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"><link rel="icon" href="faviconnew.png"><title>即时通信</title><link href="css/vendors~app.3f294141.css" rel="stylesheet"><link href="css/app.f83e8594.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but 腾讯云即时通信 Web-IM doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="./TCaptcha.js"></script><script src="./aegis.min.js"></script><script>/**
* 根据基础字体大小 和 效果图宽度设置 根节点字体大小
* @param baseFontSize 浏览器默认字体大小 [注]浏览器最小字体为12像素,所以该值必需大于等于12
* @param baseWidth 设计稿的尺寸
@@ -53,4 +53,4 @@
},
false
);
};</script><script src="js/vendors~app.be028cd5.js"></script><script src="js/app.d3bfe68a.js"></script></body></html>
};</script><script src="js/vendors~app.be028cd5.js"></script><script src="js/app.ece2c62c.js"></script></body></html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -70,7 +70,7 @@
</template>
<script setup lang="ts">
import { ref, watch, onMounted, type PropType, type Ref } from 'vue';
import { ref, watch, onMounted } from 'vue';
import { useMessage } from '/@/hooks/web/useMessage';
import { pushResourceListApi, pushSendApi, pushBatchSendApi } from './firstAidPush.api';
import { categoryListAllApi } from '/@/views/resource/resource.api';
@@ -78,7 +78,6 @@
const props = defineProps({
orderId: { type: String, default: '' },
iframeRef: { type: Object as PropType<Ref<HTMLIFrameElement>>, default: null },
hasInteractedWithIm: { type: Boolean, default: false },
});
@@ -142,29 +141,6 @@
loadList();
}
// 通过 IM iframe 的 postMessage 发送自定义消息到当前会话
// 复用 iweb 端 message-custom.vue 中 businessID='system' 的卡片渲染
function postMessageToIm(item: any) {
// Vue 3 中父组件传 ref 给子组件 prop 会自动解包,props.iframeRef 已是 iframe DOM 元素
const iframe = props.iframeRef as any;
if (!iframe?.contentWindow) {
return false;
}
const payload = {
code: 'custom',
data: {
businessID: 'system',
title: item.title,
messageImageUrl: item.coverImage || '',
content: item.summary || '',
// 唯一时间戳,避免 IM SDK 对相同 payload 去重导致重复推送不显示
_ts: Date.now(),
},
};
iframe.contentWindow.postMessage(JSON.stringify(payload), '*');
return true;
}
async function pushSingle(item: any) {
if (!props.hasInteractedWithIm) {
createMessage.warning('请先在左侧选择会话');
@@ -176,10 +152,8 @@
}
pushingId.value = item.id;
try {
// 1. 调后端接口写入推送记录(后端会触发推送通知给目标用户
// 调后端接口推送 article 卡片到当前会话(后端调用 IM 推送自定义消息
await pushSendApi({ resourceId: item.id, orderId: props.orderId });
// 2. 同时通过 IM iframe 推送卡片到当前会话(即时展示)
postMessageToIm(item);
item.pushed = true;
createMessage.success(`已推送:${item.title}`);
} finally {
@@ -203,16 +177,11 @@
}
batchLoading.value = true;
try {
// 1. 调后端接口批量推送(后端按条件查出资源并触发推送通知
// 调后端接口批量推送(后端按条件查出资源并触发 IM 推送 article 卡片
await pushBatchSendApi({
orderId: props.orderId,
resourceIds: unpushed.map((item) => item.id),
});
// 2. 同时通过 IM iframe 推送卡片到当前会话(即时展示)
for (const item of unpushed) {
postMessageToIm(item);
await new Promise((resolve) => setTimeout(resolve, 100));
}
list.value.forEach((item) => (item.pushed = true));
createMessage.success(`已推送 ${unpushed.length} 条宣教内容`);
} finally {
@@ -153,7 +153,7 @@
</a-row>
<forHelpAdv :isSpecialized="true" ref="forHelpAdvRef" />
<detail ref="detailRef" />
<FirstAidPush :orderId="orderId" :iframeRef="iframeRef" :hasInteractedWithIm="hasInteractedWithIm" />
<FirstAidPush :orderId="orderId" :hasInteractedWithIm="hasInteractedWithIm" />
</div>
</div>
</div>