IM 问卷、文章
This commit is contained in:
parent
5d03f0fc79
commit
ec27449eab
@ -25,24 +25,24 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { getArticle } from '@/utils/api.js';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import { getArticle } from "@/utils/api.js";
|
||||
import { ref } from "vue";
|
||||
const env = __VITE_ENV__;
|
||||
const corpId = env.MP_CORP_ID;
|
||||
const loading = ref(true);
|
||||
const error = ref('');
|
||||
const error = ref("");
|
||||
const articleData = ref({
|
||||
title: '',
|
||||
content: '',
|
||||
date: ''
|
||||
title: "",
|
||||
content: "",
|
||||
date: "",
|
||||
});
|
||||
|
||||
let articleId = '';
|
||||
let corpId = '';
|
||||
let articleId = "";
|
||||
|
||||
// 处理富文本内容,使图片自适应
|
||||
const processRichTextContent = (html) => {
|
||||
if (!html) return '';
|
||||
if (!html) return "";
|
||||
|
||||
// 给所有 img 标签添加样式
|
||||
let processedHtml = html.replace(
|
||||
@ -54,7 +54,7 @@ const processRichTextContent = (html) => {
|
||||
processedHtml = processedHtml.replace(
|
||||
/style="[^"]*width:\s*\d+px[^"]*"/gi,
|
||||
(match) => {
|
||||
return match.replace(/width:\s*\d+px;?/gi, 'max-width:100%;');
|
||||
return match.replace(/width:\s*\d+px;?/gi, "max-width:100%;");
|
||||
}
|
||||
);
|
||||
|
||||
@ -72,52 +72,44 @@ const processRichTextContent = (html) => {
|
||||
|
||||
// 加载文章
|
||||
const loadArticle = async () => {
|
||||
if (!articleId || !corpId) {
|
||||
error.value = '文章信息不完整';
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
error.value = '';
|
||||
|
||||
error.value = "";
|
||||
try {
|
||||
const res = await getArticle({ id: articleId, corpId: corpId });
|
||||
const res = await getArticle({ id: articleId, corpId });
|
||||
|
||||
if (res.success && res.data) {
|
||||
// 格式化日期
|
||||
let date = '';
|
||||
let date = "";
|
||||
if (res.data.createTime) {
|
||||
const d = new Date(res.data.createTime);
|
||||
const year = d.getFullYear();
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(d.getDate()).padStart(2, '0');
|
||||
const month = String(d.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(d.getDate()).padStart(2, "0");
|
||||
date = `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
articleData.value = {
|
||||
title: res.data.title || '宣教文章',
|
||||
content: processRichTextContent(res.data.content || ''),
|
||||
date: date
|
||||
title: res.data.title || "宣教文章",
|
||||
content: processRichTextContent(res.data.content || ""),
|
||||
date: date,
|
||||
};
|
||||
} else {
|
||||
error.value = res.message || '加载文章失败';
|
||||
error.value = res.message || "加载文章失败";
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('加载文章失败:', err);
|
||||
error.value = '加载失败,请重试';
|
||||
console.error("加载文章失败:", err);
|
||||
error.value = "加载失败,请重试";
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onLoad((options) => {
|
||||
if (options.id && options.corpId) {
|
||||
if (options.id) {
|
||||
articleId = options.id;
|
||||
corpId = options.corpId;
|
||||
loadArticle();
|
||||
} else {
|
||||
error.value = '文章信息不完整';
|
||||
error.value = "文章信息不完整";
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
@ -155,7 +147,7 @@ onLoad((options) => {
|
||||
|
||||
.retry-btn {
|
||||
padding: 16rpx 60rpx;
|
||||
background-color: #0877F1;
|
||||
background-color: #0877f1;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 8rpx;
|
||||
|
||||
@ -75,7 +75,8 @@
|
||||
|
||||
<view
|
||||
v-if="!loading && articleList.length >= total"
|
||||
class="no-more">
|
||||
class="no-more"
|
||||
>
|
||||
没有更多了
|
||||
</view>
|
||||
</view>
|
||||
@ -107,14 +108,26 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { getArticleCateList, getArticleList, getArticle } from "@/utils/api.js";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import {
|
||||
getArticleCateList,
|
||||
getArticleList,
|
||||
getArticle,
|
||||
sendArticleMessage,
|
||||
} from "@/utils/api.js";
|
||||
import useAccountStore from "@/store/account.js";
|
||||
import EmptyData from "@/components/empty-data.vue";
|
||||
|
||||
const env = __VITE_ENV__;
|
||||
const accountStore = useAccountStore();
|
||||
const env = __VITE_ENV__;
|
||||
const corpId = env.MP_CORP_ID;
|
||||
const userId = ref("");
|
||||
|
||||
// 从页面参数获取群组信息
|
||||
const pageParams = ref({
|
||||
groupId: "",
|
||||
userId: "",
|
||||
corpId: "",
|
||||
});
|
||||
|
||||
// 搜索关键词
|
||||
const searchTitle = ref("");
|
||||
@ -241,7 +254,7 @@ const loadMore = () => {
|
||||
|
||||
// 处理富文本内容,使图片自适应
|
||||
const processRichTextContent = (html) => {
|
||||
if (!html) return '';
|
||||
if (!html) return "";
|
||||
|
||||
// 给所有 img 标签添加样式
|
||||
let processedHtml = html.replace(
|
||||
@ -253,7 +266,7 @@ const processRichTextContent = (html) => {
|
||||
processedHtml = processedHtml.replace(
|
||||
/style="[^"]*width:\s*\d+px[^"]*"/gi,
|
||||
(match) => {
|
||||
return match.replace(/width:\s*\d+px;?/gi, 'max-width:100%;');
|
||||
return match.replace(/width:\s*\d+px;?/gi, "max-width:100%;");
|
||||
}
|
||||
);
|
||||
|
||||
@ -304,32 +317,31 @@ const closePreview = () => {
|
||||
};
|
||||
|
||||
// 发送文章
|
||||
const sendArticle = (article) => {
|
||||
// 获取当前页面栈
|
||||
const pages = getCurrentPages();
|
||||
const prevPage = pages[pages.length - 2];
|
||||
|
||||
if (prevPage) {
|
||||
// 获取医生信息
|
||||
const doctorInfo = accountStore.doctorInfo;
|
||||
userId.value = doctorInfo?.userid || accountStore.openid;
|
||||
|
||||
// 通过事件总线传递数据
|
||||
uni.$emit("sendArticle", {
|
||||
article: article,
|
||||
corpId: corpId,
|
||||
userId: userId.value,
|
||||
const sendArticle = async (article) => {
|
||||
try {
|
||||
const { doctorInfo } = useAccountStore();
|
||||
const result = await sendArticleMessage({
|
||||
groupId: pageParams.value.groupId,
|
||||
fromAccount: doctorInfo.weChatOpenId,
|
||||
articleId: article._id,
|
||||
title: article.title || "宣教文章",
|
||||
imgUrl: article.cover || "",
|
||||
desc: "点击查看详情",
|
||||
});
|
||||
|
||||
uni.showToast({
|
||||
title: "已选择文章",
|
||||
icon: "success",
|
||||
});
|
||||
|
||||
// 延迟返回,让用户看到提示
|
||||
setTimeout(() => {
|
||||
if (result.success) {
|
||||
uni.navigateBack();
|
||||
}, 500);
|
||||
} else {
|
||||
throw new Error(result.message || "发送失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("发送文章失败:", error);
|
||||
uni.showToast({
|
||||
title: error.message || "发送失败",
|
||||
icon: "none",
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
@ -338,6 +350,19 @@ const goBack = () => {
|
||||
uni.navigateBack();
|
||||
};
|
||||
|
||||
// 页面加载时接收参数
|
||||
onLoad((options) => {
|
||||
if (options.groupId) {
|
||||
pageParams.value.groupId = options.groupId;
|
||||
}
|
||||
if (options.userId) {
|
||||
pageParams.value.userId = options.userId;
|
||||
}
|
||||
if (options.corpId) {
|
||||
pageParams.value.corpId = options.corpId;
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
getCategoryList();
|
||||
loadArticleList();
|
||||
@ -400,9 +425,9 @@ onMounted(() => {
|
||||
|
||||
.category-item.active {
|
||||
background-color: #fff;
|
||||
color: #0877F1;
|
||||
color: #0877f1;
|
||||
font-weight: bold;
|
||||
border-left: 4rpx solid #0877F1;
|
||||
border-left: 4rpx solid #0877f1;
|
||||
}
|
||||
|
||||
.article-list {
|
||||
|
||||
@ -1254,11 +1254,12 @@ $primary-color: #0877F1;
|
||||
.article-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
background-color: transparent;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx;
|
||||
max-width: 500rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
|
||||
box-shadow: none;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.article-content {
|
||||
@ -1297,11 +1298,11 @@ $primary-color: #0877F1;
|
||||
|
||||
/* 文章卡片在不同消息流中的样式 */
|
||||
.message-right .article-card {
|
||||
background-color: #e8f4ff;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.message-left .article-card {
|
||||
background-color: #fff;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* 问卷卡片样式 */
|
||||
|
||||
@ -73,6 +73,9 @@ const props = defineProps({
|
||||
patientInfo: { type: Object, default: () => ({}) },
|
||||
chatRoomBusiness: { type: Object, default: () => ({}) },
|
||||
formatTime: { type: Function, required: true },
|
||||
groupId: { type: String, default: '' },
|
||||
userId: { type: String, default: '' },
|
||||
corpId: { type: String, default: '' },
|
||||
});
|
||||
|
||||
// Emits
|
||||
@ -364,7 +367,7 @@ const goToCommonPhrases = () => {
|
||||
// 跳转到宣教文章页面
|
||||
const goToArticleList = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/message/article-list'
|
||||
url: `/pages/message/article-list?groupId=${props.groupId}&userId=${props.userId}&corpId=${props.corpId}`
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -207,12 +207,12 @@ const getCustomMessageType = (message) => {
|
||||
try {
|
||||
if (message.payload && message.payload.data) {
|
||||
const data = JSON.parse(message.payload.data);
|
||||
return data.type || '';
|
||||
return data.type || "";
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('解析自定义消息失败:', error);
|
||||
console.error("解析自定义消息失败:", error);
|
||||
}
|
||||
return '';
|
||||
return "";
|
||||
};
|
||||
|
||||
// 获取文章数据
|
||||
@ -220,45 +220,25 @@ const getArticleData = (message) => {
|
||||
try {
|
||||
if (message.payload && message.payload.data) {
|
||||
const data = JSON.parse(message.payload.data);
|
||||
return {
|
||||
title: data.title || '宣教文章',
|
||||
desc: data.desc || '宣教文章',
|
||||
url: data.url || '',
|
||||
imgUrl: data.imgUrl || ''
|
||||
};
|
||||
return data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('解析文章数据失败:', error);
|
||||
console.error("解析文章数据失败:", error);
|
||||
}
|
||||
return {
|
||||
title: '宣教文章',
|
||||
desc: '宣教文章',
|
||||
url: '',
|
||||
imgUrl: ''
|
||||
title: "宣教文章",
|
||||
desc: "宣教文章",
|
||||
url: "",
|
||||
imgUrl: "",
|
||||
};
|
||||
};
|
||||
|
||||
// 处理文章点击
|
||||
const handleArticleClick = (message) => {
|
||||
const articleData = getArticleData(message);
|
||||
if (articleData.url) {
|
||||
// 提取文章ID和corpId
|
||||
const urlParams = new URLSearchParams(articleData.url.split('?')[1]);
|
||||
const articleId = urlParams.get('id');
|
||||
const corpId = urlParams.get('corpId');
|
||||
|
||||
if (articleId && corpId) {
|
||||
// 跳转到文章详情页
|
||||
uni.navigateTo({
|
||||
url: `/pages/message/article-detail?id=${articleId}&corpId=${corpId}`
|
||||
});
|
||||
} else {
|
||||
// 如果没有ID,使用webview打开链接
|
||||
uni.navigateTo({
|
||||
url: `/pages/webview/webview?url=${encodeURIComponent(articleData.url)}`
|
||||
});
|
||||
}
|
||||
}
|
||||
const { articleId } = getArticleData(message);
|
||||
uni.navigateTo({
|
||||
url: `/pages/message/article-detail?id=${articleId}`,
|
||||
});
|
||||
};
|
||||
|
||||
// 获取问卷数据
|
||||
@ -267,20 +247,20 @@ const getSurveyData = (message) => {
|
||||
if (message.payload && message.payload.data) {
|
||||
const data = JSON.parse(message.payload.data);
|
||||
return {
|
||||
title: data.title || '填写问卷',
|
||||
desc: data.desc || '请填写问卷',
|
||||
url: data.url || '',
|
||||
imgUrl: data.imgUrl || ''
|
||||
title: data.title || "填写问卷",
|
||||
desc: data.desc || "请填写问卷",
|
||||
url: data.url || "",
|
||||
imgUrl: data.imgUrl || "",
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('解析问卷数据失败:', error);
|
||||
console.error("解析问卷数据失败:", error);
|
||||
}
|
||||
return {
|
||||
title: '填写问卷',
|
||||
desc: '请填写问卷',
|
||||
url: '',
|
||||
imgUrl: ''
|
||||
title: "填写问卷",
|
||||
desc: "请填写问卷",
|
||||
url: "",
|
||||
imgUrl: "",
|
||||
};
|
||||
};
|
||||
|
||||
@ -289,7 +269,7 @@ const handleSurveyClick = (message) => {
|
||||
const surveyData = getSurveyData(message);
|
||||
if (surveyData.url) {
|
||||
// 跳转到问卷填写页面或打开外部链接
|
||||
console.log('打开问卷:', surveyData.url);
|
||||
console.log("打开问卷:", surveyData.url);
|
||||
// uni.navigateTo({
|
||||
// url: `/pages/survey/fill?url=${encodeURIComponent(surveyData.url)}`
|
||||
// });
|
||||
|
||||
@ -85,7 +85,7 @@
|
||||
}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 消息气泡 -->
|
||||
|
||||
<view class="message-bubble" :class="getBubbleClass(message)">
|
||||
<!-- 消息内容 -->
|
||||
<MessageTypes
|
||||
@ -132,6 +132,9 @@
|
||||
ref="chatInputRef"
|
||||
:timChatManager="timChatManager"
|
||||
:formatTime="formatTime"
|
||||
:groupId="chatInfo.conversationID ? chatInfo.conversationID.replace('GROUP', '') : ''"
|
||||
:userId="openid"
|
||||
:corpId="corpId"
|
||||
@scrollToBottom="() => scrollToBottom(true)"
|
||||
@messageSent="() => scrollToBottom(true)"
|
||||
@endConsult="handleEndConsult"
|
||||
@ -162,7 +165,7 @@ import {
|
||||
handleViewDetail,
|
||||
checkIMConnectionStatus,
|
||||
} from "@/utils/chat-utils.js";
|
||||
import { sendConsultRejectedMessage, endConsultation } from "@/utils/api.js";
|
||||
import { sendConsultRejectedMessage, endConsultation, sendArticleMessage } from "@/utils/api.js";
|
||||
import useGroupChat from "./hooks/use-group-chat";
|
||||
import MessageTypes from "./components/message-types.vue";
|
||||
import ChatInput from "./components/chat-input.vue";
|
||||
@ -172,6 +175,10 @@ import RejectReasonModal from "./components/reject-reason-modal.vue";
|
||||
|
||||
const timChatManager = globalTimChatManager;
|
||||
|
||||
// 获取环境变量
|
||||
const env = __VITE_ENV__;
|
||||
const corpId = env.MP_CORP_ID || '';
|
||||
|
||||
// 获取登录状态
|
||||
const { account, openid, isIMInitialized } = storeToRefs(useAccountStore());
|
||||
const { initIMAfterLogin } = useAccountStore();
|
||||
@ -300,7 +307,7 @@ function getBubbleClass(message) {
|
||||
return "image-bubble";
|
||||
}
|
||||
if (message.type === "TIMCustomElem") {
|
||||
return message.flow === "out" ? "user-bubble" : "doctor-bubble-blue";
|
||||
return message.flow === "out" ? "" : "";
|
||||
}
|
||||
return message.flow === "out" ? "user-bubble" : "doctor-bubble";
|
||||
}
|
||||
@ -696,13 +703,12 @@ onHide(() => {
|
||||
stopIMMonitoring();
|
||||
});
|
||||
|
||||
// 发送常用语(从常用语页面返回时调用)
|
||||
|
||||
const sendCommonPhrase = (content) => {
|
||||
if (chatInputRef.value) {
|
||||
chatInputRef.value.sendTextMessageFromPhrase(content);
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露方法给常用语页面调用
|
||||
defineExpose({
|
||||
sendCommonPhrase,
|
||||
@ -808,14 +814,12 @@ const handleRejectReasonConfirm = async (reason) => {
|
||||
const handleRejectReasonCancel = () => {
|
||||
showRejectReasonModal.value = false;
|
||||
};
|
||||
|
||||
// 处理结束问诊
|
||||
const handleEndConsult = async () => {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: "处理中...",
|
||||
});
|
||||
|
||||
// 调用结束问诊接口,直接传入 groupId
|
||||
const result = await endConsultation({
|
||||
groupId: groupId.value,
|
||||
@ -826,9 +830,7 @@ const handleEndConsult = async () => {
|
||||
endReason: "问诊完成",
|
||||
},
|
||||
});
|
||||
|
||||
uni.hideLoading();
|
||||
|
||||
if (result.success) {
|
||||
uni.showToast({
|
||||
title: "问诊已结束",
|
||||
@ -856,80 +858,10 @@ onUnmounted(() => {
|
||||
timChatManager.setCallback("onMessageReceived", null);
|
||||
timChatManager.setCallback("onMessageListLoaded", null);
|
||||
timChatManager.setCallback("onError", null);
|
||||
|
||||
// 移除文章发送监听
|
||||
uni.$off("sendArticle");
|
||||
// 移除问卷发送监听
|
||||
uni.$off("sendSurvey");
|
||||
});
|
||||
|
||||
// 监听文章发送事件
|
||||
uni.$on("sendArticle", async (data) => {
|
||||
const { article, corpId, userId } = data;
|
||||
|
||||
if (!article || !article._id) {
|
||||
uni.showToast({
|
||||
title: "文章信息不完整",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取环境变量
|
||||
const env = __VITE_ENV__;
|
||||
const baseUrl = env.VITE_PATIENT_PAGE_BASE_URL || "";
|
||||
|
||||
// 构建文章链接
|
||||
const articleUrl = `${baseUrl}pages/article/index?id=${article._id}&corpId=${corpId}`;
|
||||
|
||||
// 创建自定义消息
|
||||
const customMessage = {
|
||||
data: JSON.stringify({
|
||||
type: "article",
|
||||
title: article.title || "宣教文章",
|
||||
desc: "点击查看详情",
|
||||
url: articleUrl,
|
||||
imgUrl: "https://796f-youcan-clouddev-1-8ewcqf31dbb2b5-1317294507.tcb.qcloud.la/other/article-icon.png",
|
||||
articleId: article._id
|
||||
}),
|
||||
description: "ARTICLE",
|
||||
extension: "",
|
||||
};
|
||||
|
||||
// 发送自定义消息
|
||||
const message = timChatManager.tim.createCustomMessage({
|
||||
to: chatInfo.value.conversationID.replace("GROUP", ""),
|
||||
conversationType: timChatManager.TIM.TYPES.CONV_GROUP,
|
||||
payload: customMessage,
|
||||
});
|
||||
|
||||
const sendResult = await timChatManager.tim.sendMessage(message);
|
||||
|
||||
if (sendResult.code === 0) {
|
||||
uni.showToast({
|
||||
title: "发送成功",
|
||||
icon: "success",
|
||||
});
|
||||
|
||||
// 记录发送记录(可选)
|
||||
// await addArticleSendRecord({
|
||||
// corpId,
|
||||
// userId,
|
||||
// articleId: article._id,
|
||||
// customerId: chatInfo.value.userID
|
||||
// });
|
||||
} else {
|
||||
throw new Error(sendResult.message || "发送失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("发送文章失败:", error);
|
||||
uni.showToast({
|
||||
title: error.message || "发送失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 监听问卷发送事件
|
||||
uni.$on("sendSurvey", async (data) => {
|
||||
@ -942,7 +874,6 @@ uni.$on("sendSurvey", async (data) => {
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取环境变量
|
||||
const env = __VITE_ENV__;
|
||||
|
||||
11
utils/api.js
11
utils/api.js
@ -144,6 +144,17 @@ export async function sendConsultRejectedMessage(data) {
|
||||
});
|
||||
}
|
||||
|
||||
// 发送宣教文章消息
|
||||
export async function sendArticleMessage(data) {
|
||||
return request({
|
||||
url: '/getYoucanData/im',
|
||||
data: {
|
||||
type: 'sendArticleMessage',
|
||||
...data
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 结束问诊接口
|
||||
export async function endConsultation(data) {
|
||||
return request({
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user