Merge remote-tracking branch 'origin/dev-订阅消息' into dev-2.3
This commit is contained in:
commit
ba49a144ab
@ -7,10 +7,10 @@
|
||||
@add-patient="handleAddPatient"
|
||||
/>
|
||||
<!-- 消息列表 -->
|
||||
<scroll-view
|
||||
class="message-list"
|
||||
scroll-y="true"
|
||||
refresher-enabled
|
||||
<scroll-view
|
||||
class="message-list"
|
||||
scroll-y="true"
|
||||
refresher-enabled
|
||||
:refresher-triggered="refreshing"
|
||||
@refresherrefresh="handleRefresh"
|
||||
@scrolltolower="handleLoadMore"
|
||||
@ -83,22 +83,31 @@
|
||||
>
|
||||
<text class="load-more-text">{{
|
||||
loadingMore ? "加载中..." : "上拉加载更多"
|
||||
}}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from "vue";
|
||||
}}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="subscribe-entry" @click="handleSubscribeReminder">
|
||||
<text class="subscribe-entry-text">接收提醒</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from "vue";
|
||||
import { onLoad, onShow, onHide } from "@dcloudio/uni-app";
|
||||
import { storeToRefs } from "pinia";
|
||||
import useAccountStore from "@/store/account.js";
|
||||
import useTeamStore from "@/store/team.js";
|
||||
import useInfoCheck from "@/hooks/useInfoCheck.js";
|
||||
import { globalTimChatManager } from "@/utils/tim-chat.js";
|
||||
import { mergeConversationWithGroupDetails } from "@/utils/conversation-merger.js";
|
||||
import MessageHeader from "../home/components/message-header.vue";
|
||||
import useInfoCheck from "@/hooks/useInfoCheck.js";
|
||||
import { globalTimChatManager } from "@/utils/tim-chat.js";
|
||||
import { mergeConversationWithGroupDetails } from "@/utils/conversation-merger.js";
|
||||
import MessageHeader from "../home/components/message-header.vue";
|
||||
import { requestConversationSubscribeMessage } from "@/utils/subscribe-message";
|
||||
import {
|
||||
SUBSCRIBE_MESSAGE_ROLE,
|
||||
SUBSCRIBE_MESSAGE_SCENE,
|
||||
} from "@/utils/subscribe-message-config";
|
||||
|
||||
// 获取登录状态
|
||||
const { account, openid, isIMInitialized, doctorInfo } = storeToRefs(
|
||||
@ -633,14 +642,29 @@ const handleLoadMore = () => {
|
||||
};
|
||||
|
||||
// 下拉刷新
|
||||
const handleRefresh = async () => {
|
||||
refreshing.value = true;
|
||||
try {
|
||||
await loadConversationList();
|
||||
} finally {
|
||||
refreshing.value = false;
|
||||
}
|
||||
};
|
||||
const handleRefresh = async () => {
|
||||
refreshing.value = true;
|
||||
try {
|
||||
await loadConversationList();
|
||||
} finally {
|
||||
refreshing.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubscribeReminder = async () => {
|
||||
await requestConversationSubscribeMessage({
|
||||
role: SUBSCRIBE_MESSAGE_ROLE.DOCTOR,
|
||||
scene: SUBSCRIBE_MESSAGE_SCENE.LIST,
|
||||
userId: doctorInfo.value?.userid || account.value?.userId || "",
|
||||
openid: openid.value || account.value?.openid || "",
|
||||
unionid: account.value?.unionid || "",
|
||||
doctorId: doctorInfo.value?.userid || "",
|
||||
extraData: {
|
||||
teamId: currentTeamId.value || "",
|
||||
page: "pages/home/message-home",
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 页面加载
|
||||
onLoad(() => {
|
||||
@ -840,8 +864,36 @@ onHide(() => {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.load-more-text {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
||||
.load-more-text {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.subscribe-entry {
|
||||
position: fixed;
|
||||
right: 32rpx;
|
||||
bottom: 180rpx;
|
||||
width: 116rpx;
|
||||
height: 116rpx;
|
||||
border-radius: 58rpx;
|
||||
background: #fff;
|
||||
border: 2rpx solid #3876f6;
|
||||
box-shadow: 0 8rpx 24rpx rgba(56, 118, 246, 0.16);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.subscribe-entry:active {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.subscribe-entry-text {
|
||||
width: 56rpx;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.4;
|
||||
color: #3876f6;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -29,6 +29,13 @@ $primary-color: #0877F1;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.patient-basic-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -76,6 +83,26 @@ $primary-color: #0877F1;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.remind-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10rpx 20rpx;
|
||||
border-radius: 24rpx;
|
||||
border: 2rpx solid #3876f6;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.remind-btn:active {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.remind-btn-text {
|
||||
font-size: 24rpx;
|
||||
color: #3876f6;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.arrow-icon {
|
||||
font-size: 32rpx;
|
||||
color: #fff;
|
||||
|
||||
@ -3,17 +3,22 @@
|
||||
<!-- 患者信息栏 -->
|
||||
<view class="patient-info-bar" v-if="patientInfo.name">
|
||||
<view class="patient-info-content">
|
||||
<view class="patient-basic-info">
|
||||
<text class="patient-name">{{ patientInfo.name }}</text>
|
||||
<text class="patient-detail"
|
||||
>{{ patientInfo.sex }} · {{ patientInfo.age }}岁</text
|
||||
>
|
||||
</view>
|
||||
<view class="patient-detail-btn" @click="handleViewPatientDetail">
|
||||
<text class="detail-btn-text">查看档案</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="patient-basic-info">
|
||||
<text class="patient-name">{{ patientInfo.name }}</text>
|
||||
<text class="patient-detail"
|
||||
>{{ patientInfo.sex }} · {{ patientInfo.age }}岁</text
|
||||
>
|
||||
</view>
|
||||
<view class="header-actions">
|
||||
<view class="patient-detail-btn" @click="handleViewPatientDetail">
|
||||
<text class="detail-btn-text">查看档案</text>
|
||||
</view>
|
||||
<view class="remind-btn" @click="handleSubscribeReminder">
|
||||
<text class="remind-btn-text">接收提醒</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 聊天消息区域 -->
|
||||
<scroll-view
|
||||
@ -222,11 +227,16 @@ import MessageTypes from "./components/message-types.vue";
|
||||
import ChatInput from "./components/chat-input.vue";
|
||||
import SystemMessage from "./components/system-message.vue";
|
||||
import ConsultAccept from "./components/consult-accept.vue";
|
||||
import RejectReasonModal from "./components/reject-reason-modal.vue";
|
||||
import AIAssistantButtons from "./components/ai-assistant-buttons.vue";
|
||||
import MedicalCaseTypeSelector from "./components/medical-case-type-selector.vue";
|
||||
import MedicalCaseProgress from "./components/medical-case-progress.vue";
|
||||
import request from "@/utils/http.js";
|
||||
import RejectReasonModal from "./components/reject-reason-modal.vue";
|
||||
import AIAssistantButtons from "./components/ai-assistant-buttons.vue";
|
||||
import MedicalCaseTypeSelector from "./components/medical-case-type-selector.vue";
|
||||
import MedicalCaseProgress from "./components/medical-case-progress.vue";
|
||||
import request from "@/utils/http.js";
|
||||
import { requestConversationSubscribeMessage } from "@/utils/subscribe-message";
|
||||
import {
|
||||
SUBSCRIBE_MESSAGE_ROLE,
|
||||
SUBSCRIBE_MESSAGE_SCENE,
|
||||
} from "@/utils/subscribe-message-config";
|
||||
|
||||
const timChatManager = globalTimChatManager;
|
||||
|
||||
@ -298,7 +308,9 @@ const env = __VITE_ENV__;
|
||||
const corpId = env.MP_CORP_ID || "";
|
||||
|
||||
// 获取登录状态
|
||||
const { account, openid, isIMInitialized } = storeToRefs(useAccountStore());
|
||||
const { account, openid, isIMInitialized, doctorInfo } = storeToRefs(
|
||||
useAccountStore()
|
||||
);
|
||||
const { initIMAfterLogin } = useAccountStore();
|
||||
|
||||
// 聊天输入组件引用
|
||||
@ -1242,21 +1254,42 @@ const handleRejectReasonCancel = () => {
|
||||
};
|
||||
|
||||
// 处理查看患者详情
|
||||
const handleViewPatientDetail = () => {
|
||||
if (!patientId.value) {
|
||||
uni.showToast({
|
||||
title: "患者信息不完整",
|
||||
const handleViewPatientDetail = () => {
|
||||
if (!patientId.value) {
|
||||
uni.showToast({
|
||||
title: "患者信息不完整",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
uni.navigateTo({
|
||||
url: `/pages/case/archive-detail?id=${patientId.value}`,
|
||||
});
|
||||
};
|
||||
// 处理结束问诊
|
||||
const handleEndConsult = async () => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/case/archive-detail?id=${patientId.value}`,
|
||||
});
|
||||
};
|
||||
|
||||
const handleSubscribeReminder = async () => {
|
||||
await requestConversationSubscribeMessage({
|
||||
role: SUBSCRIBE_MESSAGE_ROLE.DOCTOR,
|
||||
scene: SUBSCRIBE_MESSAGE_SCENE.CHAT,
|
||||
conversationId: chatInfo.value.conversationID || "",
|
||||
groupId: groupId.value || "",
|
||||
corpId: corpId || "",
|
||||
teamId: teamId.value || "",
|
||||
patientId: patientId.value || "",
|
||||
doctorId: doctorInfo.value?.userid || "",
|
||||
userId: doctorInfo.value?.userid || account.value?.userId || "",
|
||||
openid: openid.value || account.value?.openid || "",
|
||||
unionid: account.value?.unionid || "",
|
||||
extraData: {
|
||||
orderStatus: orderStatus.value || "",
|
||||
page: "pages/message/index",
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 处理结束问诊
|
||||
const handleEndConsult = async () => {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: "处理中...",
|
||||
|
||||
@ -111,7 +111,9 @@ const urlsConfig = {
|
||||
getGroupList: "getGroupList",
|
||||
followUpInquiry: "followUpInquiry",
|
||||
supplementMedicalCase: "supplementMedicalCase",
|
||||
rejectConsultation: "rejectConsultation"
|
||||
rejectConsultation: "rejectConsultation",
|
||||
saveConversationSubscribeResult: "saveConversationSubscribeResult",
|
||||
sendConversationSubscribeEvent: "sendConversationSubscribeEvent"
|
||||
},
|
||||
todo: {
|
||||
getCustomerTodos: 'getCustomerTodos',
|
||||
|
||||
63
utils/subscribe-message-config.js
Normal file
63
utils/subscribe-message-config.js
Normal file
@ -0,0 +1,63 @@
|
||||
const env = __VITE_ENV__;
|
||||
|
||||
export const SUBSCRIBE_MESSAGE_ROLE = {
|
||||
PATIENT: "patient",
|
||||
DOCTOR: "doctor",
|
||||
};
|
||||
|
||||
export const SUBSCRIBE_MESSAGE_SCENE = {
|
||||
DEFAULT: "default",
|
||||
LIST: "list",
|
||||
CHAT: "chat",
|
||||
};
|
||||
|
||||
export const SUBSCRIBE_MESSAGE_EVENT = {
|
||||
PATIENT_CONSULT_APPLY: "patient_consult_apply",
|
||||
PATIENT_CHAT_MESSAGE: "patient_chat_message",
|
||||
DOCTOR_ACCEPT: "doctor_accept",
|
||||
DOCTOR_REJECT: "doctor_reject",
|
||||
DOCTOR_CHAT_MESSAGE: "doctor_chat_message",
|
||||
};
|
||||
|
||||
export const SUBSCRIBE_MESSAGE_TEMPLATES = {
|
||||
consultationReply: {
|
||||
code: "consultationReply",
|
||||
role: SUBSCRIBE_MESSAGE_ROLE.DOCTOR,
|
||||
id:
|
||||
env.MP_SUBSCRIBE_TEMPLATE_CONSULT_REPLY ||
|
||||
"1etY1Mdfz9c0xJlI8kx79Re6uKmc3BoHJBHsrXeiCm4",
|
||||
name: "咨询回复通知",
|
||||
events: [
|
||||
SUBSCRIBE_MESSAGE_EVENT.PATIENT_CONSULT_APPLY,
|
||||
SUBSCRIBE_MESSAGE_EVENT.PATIENT_CHAT_MESSAGE,
|
||||
],
|
||||
fields: ["咨询人", "回复时间", "回复内容"],
|
||||
},
|
||||
};
|
||||
|
||||
export const SUBSCRIBE_MESSAGE_SCENE_TEMPLATE_MAP = {
|
||||
[SUBSCRIBE_MESSAGE_ROLE.DOCTOR]: {
|
||||
[SUBSCRIBE_MESSAGE_SCENE.DEFAULT]: ["consultationReply"],
|
||||
[SUBSCRIBE_MESSAGE_SCENE.LIST]: ["consultationReply"],
|
||||
[SUBSCRIBE_MESSAGE_SCENE.CHAT]: ["consultationReply"],
|
||||
},
|
||||
};
|
||||
|
||||
export function resolveSubscribeTemplates({
|
||||
role,
|
||||
scene = SUBSCRIBE_MESSAGE_SCENE.DEFAULT,
|
||||
} = {}) {
|
||||
const roleMap = SUBSCRIBE_MESSAGE_SCENE_TEMPLATE_MAP[role] || {};
|
||||
const keys =
|
||||
roleMap[scene] || roleMap[SUBSCRIBE_MESSAGE_SCENE.DEFAULT] || [];
|
||||
const seen = new Set();
|
||||
|
||||
return keys
|
||||
.map((key) => SUBSCRIBE_MESSAGE_TEMPLATES[key])
|
||||
.filter((item) => item && item.id)
|
||||
.filter((item) => {
|
||||
if (seen.has(item.id)) return false;
|
||||
seen.add(item.id);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
194
utils/subscribe-message.js
Normal file
194
utils/subscribe-message.js
Normal file
@ -0,0 +1,194 @@
|
||||
import api from "@/utils/api";
|
||||
import { toast } from "@/utils/widget";
|
||||
import { resolveSubscribeTemplates } from "./subscribe-message-config";
|
||||
|
||||
const SUBSCRIBE_ACCEPT_STATUS = "accept";
|
||||
const SUBSCRIBE_REJECT_STATUS = "reject";
|
||||
const SUBSCRIBE_BAN_STATUS = "ban";
|
||||
const SUBSCRIBE_FILTER_STATUS = "filter";
|
||||
const SUBSCRIBE_CANCEL_STATUS = "cancel";
|
||||
const SUBSCRIBE_FAILED_STATUS = "failed";
|
||||
|
||||
function canUseSubscribeMessage() {
|
||||
return (
|
||||
typeof wx !== "undefined" &&
|
||||
typeof wx.requestSubscribeMessage === "function"
|
||||
);
|
||||
}
|
||||
|
||||
function requestSubscribeMessage(tmplIds = []) {
|
||||
return new Promise((resolve) => {
|
||||
wx.requestSubscribeMessage({
|
||||
tmplIds,
|
||||
success(res) {
|
||||
resolve({ ok: true, res });
|
||||
},
|
||||
fail(err) {
|
||||
resolve({ ok: false, err });
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeFailStatus(err = {}) {
|
||||
const errCode = Number(err.errCode || 0);
|
||||
const errMsg = String(err.errMsg || "").toLowerCase();
|
||||
|
||||
if (errCode === 20004 || errMsg.includes("main switch")) {
|
||||
return SUBSCRIBE_BAN_STATUS;
|
||||
}
|
||||
if (errCode === 20005 || errMsg.includes("ban")) {
|
||||
return SUBSCRIBE_BAN_STATUS;
|
||||
}
|
||||
if (errMsg.includes("filter")) {
|
||||
return SUBSCRIBE_FILTER_STATUS;
|
||||
}
|
||||
if (errMsg.includes("cancel")) {
|
||||
return SUBSCRIBE_CANCEL_STATUS;
|
||||
}
|
||||
return SUBSCRIBE_FAILED_STATUS;
|
||||
}
|
||||
|
||||
function buildTemplateResultRecords(templates = [], requestResult = {}, context = {}) {
|
||||
const requestedAt = Date.now();
|
||||
|
||||
if (requestResult.ok) {
|
||||
const res = requestResult.res || {};
|
||||
return templates.map((template) => ({
|
||||
role: context.role || "",
|
||||
scene: context.scene || "",
|
||||
conversationId: context.conversationId || "",
|
||||
groupId: context.groupId || "",
|
||||
corpId: context.corpId || "",
|
||||
teamId: context.teamId || "",
|
||||
patientId: context.patientId || "",
|
||||
doctorId: context.doctorId || "",
|
||||
userId: context.userId || "",
|
||||
openid: context.openid || "",
|
||||
unionid: context.unionid || "",
|
||||
templateId: template.id,
|
||||
templateCode: template.code,
|
||||
templateName: template.name,
|
||||
eventTypes: template.events,
|
||||
status: String(res[template.id] || SUBSCRIBE_FAILED_STATUS),
|
||||
rawResult: res,
|
||||
requestedAt,
|
||||
extraData: context.extraData || {},
|
||||
}));
|
||||
}
|
||||
|
||||
const status = normalizeFailStatus(requestResult.err);
|
||||
return templates.map((template) => ({
|
||||
role: context.role || "",
|
||||
scene: context.scene || "",
|
||||
conversationId: context.conversationId || "",
|
||||
groupId: context.groupId || "",
|
||||
corpId: context.corpId || "",
|
||||
teamId: context.teamId || "",
|
||||
patientId: context.patientId || "",
|
||||
doctorId: context.doctorId || "",
|
||||
userId: context.userId || "",
|
||||
openid: context.openid || "",
|
||||
unionid: context.unionid || "",
|
||||
templateId: template.id,
|
||||
templateCode: template.code,
|
||||
templateName: template.name,
|
||||
eventTypes: template.events,
|
||||
status,
|
||||
rawResult: requestResult.err || {},
|
||||
requestedAt,
|
||||
extraData: context.extraData || {},
|
||||
}));
|
||||
}
|
||||
|
||||
function buildToastMessage(records = [], reportResult = { success: false }) {
|
||||
const accepted = records.some((item) => item.status === SUBSCRIBE_ACCEPT_STATUS);
|
||||
|
||||
if (accepted && reportResult?.success === false) {
|
||||
return reportResult?.message || "提醒开启失败,请稍后再试";
|
||||
}
|
||||
|
||||
if (records.some((item) => item.status === SUBSCRIBE_ACCEPT_STATUS)) {
|
||||
return "会话消息提醒开启";
|
||||
}
|
||||
if (records.some((item) => item.status === SUBSCRIBE_BAN_STATUS)) {
|
||||
return "请先在微信设置中开启订阅消息提醒";
|
||||
}
|
||||
if (records.some((item) => item.status === SUBSCRIBE_FILTER_STATUS)) {
|
||||
return "当前提醒模板暂不可用";
|
||||
}
|
||||
if (records.some((item) => item.status === SUBSCRIBE_REJECT_STATUS)) {
|
||||
return "你已拒绝本次提醒订阅";
|
||||
}
|
||||
if (records.some((item) => item.status === SUBSCRIBE_CANCEL_STATUS)) {
|
||||
return "你已取消本次提醒订阅";
|
||||
}
|
||||
return "提醒订阅请求失败,请稍后再试";
|
||||
}
|
||||
|
||||
async function reportSubscribeResult(records = []) {
|
||||
if (!records.length) return { success: false };
|
||||
try {
|
||||
return await api(
|
||||
"saveConversationSubscribeResult",
|
||||
{
|
||||
records,
|
||||
},
|
||||
false
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("保存订阅结果失败:", error);
|
||||
return { success: false, message: error?.message || "保存失败" };
|
||||
}
|
||||
}
|
||||
|
||||
export async function requestConversationSubscribeMessage(context = {}) {
|
||||
const templates = resolveSubscribeTemplates({
|
||||
role: context.role,
|
||||
scene: context.scene,
|
||||
});
|
||||
const requestTemplates = templates.slice(0, 1);
|
||||
|
||||
if (!requestTemplates.length) {
|
||||
await toast("暂未配置提醒模板");
|
||||
return {
|
||||
success: false,
|
||||
code: "template_missing",
|
||||
records: [],
|
||||
};
|
||||
}
|
||||
|
||||
if (!canUseSubscribeMessage()) {
|
||||
await toast("当前微信版本不支持订阅消息");
|
||||
return {
|
||||
success: false,
|
||||
code: "unsupported",
|
||||
records: [],
|
||||
};
|
||||
}
|
||||
|
||||
const requestResult = await requestSubscribeMessage(
|
||||
requestTemplates.map((item) => item.id)
|
||||
);
|
||||
const records = buildTemplateResultRecords(
|
||||
requestTemplates,
|
||||
requestResult,
|
||||
context
|
||||
);
|
||||
|
||||
const reportResult = await reportSubscribeResult(records);
|
||||
await toast(buildToastMessage(records, reportResult));
|
||||
|
||||
const subscribeSuccess =
|
||||
records.some((item) => item.status === SUBSCRIBE_ACCEPT_STATUS) &&
|
||||
reportResult?.success !== false;
|
||||
|
||||
return {
|
||||
success: subscribeSuccess,
|
||||
reportResult,
|
||||
records,
|
||||
acceptedTemplateIds: records
|
||||
.filter((item) => item.status === SUBSCRIBE_ACCEPT_STATUS)
|
||||
.map((item) => item.templateId),
|
||||
};
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user