定时拉取聊天记录

This commit is contained in:
2026-05-07 17:36:00 +08:00
parent b6e6394e51
commit 36847ea70c
5 changed files with 114 additions and 11 deletions
+5
View File
@@ -261,6 +261,11 @@ export function getImChatMessages(params: { diagnosis_id: number; only_archived?
return request.get({ url: '/tcm.diagnosis/getImChatMessages', params })
}
/** 触发后台异步同步:从腾讯云 IM 拉取诊单聊天记录入归档表,请求即返回 */
export function triggerImChatSync(data: { diagnosis_id: number }) {
return request.post({ url: '/tcm.diagnosis/triggerImChatSync', data })
}
// 获取企业微信聊天记录
export function getWechatChatRecords(params: any) {
return request.get({ url: '/tcm.diagnosis/getWechatChatRecords', params })
@@ -4,14 +4,18 @@
<p class="panel-tip">
展示单聊记录已合并患者
<strong>所有医生 / 医助账号</strong>分别产生的会话按时间排序
数据来自 IM 漫游若未开通漫游或某账号与该患者无会话对应侧无消息
数据由后台定时任务从腾讯云 IM 漫游消息同步至本地归档点击下方按钮可立即触发后台同步
</p>
</el-alert>
<div class="toolbar mb-3">
<el-button type="primary" link :loading="loading" @click="refreshLive">
<el-button type="primary" link :loading="syncing" @click="triggerSync">
<el-icon class="mr-1"><Promotion /></el-icon>
同步最新后台异步
</el-button>
<el-button type="primary" link :loading="loading" @click="reloadArchived">
<el-icon class="mr-1"><Refresh /></el-icon>
刷新同步云端最新
重新加载已归档
</el-button>
</div>
@@ -68,8 +72,9 @@
<script setup lang="ts">
import { ref, shallowRef, watch, computed } from 'vue'
import dayjs from 'dayjs'
import { Refresh } from '@element-plus/icons-vue'
import { getImChatMessages } from '@/api/tcm'
import { Refresh, Promotion } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { getImChatMessages, triggerImChatSync } from '@/api/tcm'
import type { FriendlyParse } from '@/utils/im-business-message-parse'
import { parseImBusinessPayload } from '@/utils/im-business-message-parse'
@@ -78,6 +83,7 @@ const props = defineProps<{
}>()
const loading = ref(false)
const syncing = ref(false)
const rawRows = shallowRef<any[]>([])
const patientImId = ref('')
const patientName = ref('')
@@ -139,13 +145,13 @@ function senderLabel(row: any) {
return patientName.value ? `患者(${patientName.value}` : '患者'
}
async function load(onlyArchived = false) {
async function load() {
if (!props.diagnosisId) return
loading.value = true
try {
const res = (await getImChatMessages({
diagnosis_id: props.diagnosisId,
only_archived: onlyArchived ? 1 : 0
only_archived: 1
})) as {
lists?: any[]
patient_im_id?: string
@@ -162,19 +168,33 @@ async function load(onlyArchived = false) {
}
}
function refreshLive() {
load(false)
function reloadArchived() {
load()
}
async function triggerSync() {
if (!props.diagnosisId) return
syncing.value = true
try {
await triggerImChatSync({ diagnosis_id: props.diagnosisId })
ElMessage.success('已发起后台同步,几秒后请点击"重新加载已归档"查看新消息')
} catch (e) {
console.error(e)
ElMessage.error('发起同步失败')
} finally {
syncing.value = false
}
}
watch(
() => props.diagnosisId,
() => {
load(true)
load()
},
{ immediate: true }
)
defineExpose({ refresh: refreshLive })
defineExpose({ refresh: reloadArchived })
</script>
<style scoped lang="scss">
@@ -407,6 +407,36 @@ class DiagnosisController extends BaseAdminController
return $this->data($result);
}
/**
* @notes 触发后台异步同步当前诊单的腾讯云 IM 聊天记录到本地归档表
* 请求即返回,真正的同步逻辑在 fastcgi_finish_request 之后执行
*/
public function triggerImChatSync()
{
$diagnosisId = (int)$this->request->post('diagnosis_id', 0);
if ($diagnosisId <= 0) {
$diagnosisId = (int)$this->request->get('diagnosis_id', 0);
}
if ($diagnosisId <= 0) {
return $this->fail('诊单ID不能为空');
}
register_shutdown_function(function () use ($diagnosisId) {
try {
@set_time_limit(300);
ignore_user_abort(true);
DiagnosisLogic::syncImChatArchiveForDiagnosis($diagnosisId);
} catch (\Throwable $e) {
\think\facade\Log::warning('triggerImChatSync failed', [
'diagnosis_id' => $diagnosisId,
'err' => $e->getMessage(),
]);
}
});
return $this->success('已发起后台同步,几秒后请重新加载查看', ['queued' => true]);
}
/**
* @notes 绑定 TRTC 房间号到当前诊单通话记录(便于云端录制回调关联)
* @return \think\response\Json
@@ -0,0 +1,20 @@
-- 注册「同步诊单 IM 聊天记录归档」定时任务,每 30 分钟跑一次
-- 命令本体:server/app/common/command/SyncImChatArchive.php,已在 server/config/console.php 注册为 sync_im_chat_archive
-- 参数:--since-days=7 仅处理最近 7 天有更新的诊单,--limit=200 单轮最多处理 200 个诊单
-- expression 字段为 5 段标准 cron(分 时 日 月 周),与 likeadmin la_dev_crontab 保持一致
INSERT INTO `zyt_dev_crontab` (
`name`, `type`, `system`, `remark`, `command`, `params`,
`status`, `expression`, `create_time`, `update_time`
) VALUES (
'同步诊单IM聊天记录',
1,
0,
'从腾讯云 IM 拉取近 7 天有更新诊单的漫游消息归档到 tcm_im_chat_message',
'sync_im_chat_archive',
'--since-days=7 --limit=200',
1,
'*/30 * * * *',
UNIX_TIMESTAMP(),
UNIX_TIMESTAMP()
);
@@ -0,0 +1,28 @@
-- 诊单腾讯云 IM 单聊消息归档(定时从 admin_getroammsg 同步,突破云端约 7 天漫游限制)
-- 已在生产部分环境创建(参见 server/database/migrations/create_tcm_im_chat_message.sql
-- 此处使用 IF NOT EXISTS 安全重入,确保新环境部署时一并建表
CREATE TABLE IF NOT EXISTS `zyt_tcm_im_chat_message` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`diagnosis_id` int unsigned NOT NULL DEFAULT 0 COMMENT '诊单ID',
`patient_id` int unsigned NOT NULL DEFAULT 0 COMMENT '患者ID(冗余,便于按患者维度排查/统计)',
`msg_id` varchar(160) NOT NULL DEFAULT '' COMMENT '业务唯一键:MsgSeq_MsgRandom_From_Account',
`from_account` varchar(64) NOT NULL DEFAULT '' COMMENT '发送方 IM UserID',
`to_account` varchar(64) NOT NULL DEFAULT '' COMMENT '接收方 IM UserID',
`msg_time` int unsigned NOT NULL DEFAULT 0 COMMENT '消息时间 Unix 时间戳',
`is_from_doctor` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '是否医生/医助侧发送',
`msg_type` varchar(32) NOT NULL DEFAULT '' COMMENT 'text/image/file/sound/video/custom/...',
`text` mediumtext COMMENT '文本或自定义消息 Data',
`image_url` varchar(1024) NOT NULL DEFAULT '' COMMENT '图片 URL',
`file_url` varchar(1024) NOT NULL DEFAULT '' COMMENT '文件/语音/视频 URL',
`file_name` varchar(512) NOT NULL DEFAULT '' COMMENT '文件名',
`raw_elem_type` varchar(64) NOT NULL DEFAULT '' COMMENT 'TIM 元素类型',
`from_staff_name` varchar(64) NOT NULL DEFAULT '' COMMENT '医生侧姓名快照',
`doctor_peer_account` varchar(64) NOT NULL DEFAULT '' COMMENT '拉取会话时使用的医生侧账号 doctor_*',
`create_time` int unsigned NOT NULL DEFAULT 0 COMMENT '入库时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_msg_id` (`msg_id`),
KEY `idx_diagnosis_time` (`diagnosis_id`,`msg_time`),
KEY `idx_patient_time` (`patient_id`,`msg_time`),
KEY `idx_msg_time` (`msg_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='诊单IM聊天记录归档';