Merge remote-tracking branch 'origin/dev-hjf' into dev-wdb
This commit is contained in:
commit
9faad813df
@ -91,13 +91,11 @@
|
||||
</view>
|
||||
</view>
|
||||
<button
|
||||
v-if="fromChat && isExecutor(i)"
|
||||
v-if="canShowSendButton(i)"
|
||||
class="action-btn send-btn"
|
||||
:class="{ loading: sendingFollowUp }"
|
||||
:disabled="sendingFollowUp"
|
||||
@click.stop="sendFollowUp(i)"
|
||||
@click.stop="goChatAndSend(i)"
|
||||
>
|
||||
{{ sendingFollowUp ? "发送中..." : "发送" }}
|
||||
发送
|
||||
</button>
|
||||
</view>
|
||||
<view v-if="i.status === 'treated'" class="result"
|
||||
@ -304,7 +302,6 @@ const pages = ref(1);
|
||||
const loading = ref(false);
|
||||
|
||||
const userNameMap = ref({});
|
||||
const sendingFollowUp = ref(false);
|
||||
|
||||
const moreStatus = computed(() => {
|
||||
if (loading.value) return "loading";
|
||||
@ -383,11 +380,43 @@ function resolveUserName(userId) {
|
||||
}
|
||||
|
||||
function refreshChatRoom() {
|
||||
if (!props.fromChat) return;
|
||||
const pending = uni.getStorageSync(PENDING_FOLLOWUP_SEND_STORAGE_KEY);
|
||||
if (pending && typeof pending === "object") {
|
||||
chatGroupId.value = String(pending.chatGroupId || pending.groupId || "");
|
||||
// 兼容:优先用档案详情数据里已有的 chatGroupId
|
||||
const fromArchive =
|
||||
props?.data && typeof props.data === "object" ? props.data : {};
|
||||
const direct = String(fromArchive?.chatGroupId || fromArchive?.groupId || "");
|
||||
if (direct) {
|
||||
chatGroupId.value = direct;
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果没有,走接口探测可用会话
|
||||
refreshChatRoomByApi();
|
||||
}
|
||||
|
||||
function getConversationIdForChat(groupId) {
|
||||
const gid = normalizeGroupId(groupId || "");
|
||||
return gid ? `GROUP${gid}` : "";
|
||||
}
|
||||
|
||||
function hasSendContent(todo) {
|
||||
return (
|
||||
Boolean(todo?.sendContent) ||
|
||||
(Array.isArray(todo?.fileList) && todo.fileList.length > 0)
|
||||
);
|
||||
}
|
||||
|
||||
function isExecutorMe(todo) {
|
||||
const me = String(getUserId() || "");
|
||||
const executor = String(todo?.executorUserId || "");
|
||||
if (!me || !executor) return false;
|
||||
return me === executor;
|
||||
}
|
||||
|
||||
function canShowSendButton(todo) {
|
||||
if (!hasSendContent(todo)) return false;
|
||||
if (!isExecutorMe(todo)) return false;
|
||||
// 当前患者无会话则不展示
|
||||
return Boolean(currentChatGroupId.value);
|
||||
}
|
||||
|
||||
function formatTodo(todo) {
|
||||
@ -558,90 +587,153 @@ function toDetail(todo) {
|
||||
});
|
||||
}
|
||||
|
||||
async function sendFollowUp(todo) {
|
||||
if (sendingFollowUp.value) {
|
||||
toast("正在发送中,请稍候...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!todo.sendContent && (!todo.fileList || todo.fileList.length === 0)) {
|
||||
toast("没有发送内容");
|
||||
return;
|
||||
}
|
||||
|
||||
sendingFollowUp.value = true;
|
||||
try {
|
||||
function buildFollowUpMessages(todo) {
|
||||
const messages = [];
|
||||
|
||||
// 1. 发送文字内容
|
||||
if (todo.sendContent) {
|
||||
messages.push({
|
||||
type: "text",
|
||||
content: todo.sendContent,
|
||||
});
|
||||
if (todo?.sendContent) {
|
||||
messages.push({ type: "text", content: String(todo.sendContent) });
|
||||
}
|
||||
console.log("==============>fileList", todo.fileList);
|
||||
|
||||
// 2. 处理文件列表(图片、宣教文章、问卷)
|
||||
if (Array.isArray(todo.fileList)) {
|
||||
if (Array.isArray(todo?.fileList)) {
|
||||
for (const file of todo.fileList) {
|
||||
if (file.type === "image" && file.URL) {
|
||||
// 发送图片
|
||||
const outerType = String(file?.type || "");
|
||||
|
||||
let innerFile = file?.file;
|
||||
if (typeof innerFile === "string") {
|
||||
try {
|
||||
innerFile = JSON.parse(innerFile);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
innerFile = innerFile && typeof innerFile === "object" ? innerFile : null;
|
||||
|
||||
const innerType = String(innerFile?.type || "");
|
||||
const outerUrl = String(file?.URL || file?.url || "");
|
||||
const innerUrl = String(innerFile?.url || "");
|
||||
|
||||
let fileType = "";
|
||||
if (outerType === "image" || innerType.includes("image")) fileType = "image";
|
||||
else if (innerType === "article") fileType = "article";
|
||||
else if (innerType === "questionnaire") fileType = "questionnaire";
|
||||
else fileType = outerType;
|
||||
|
||||
const url =
|
||||
fileType === "article" || fileType === "questionnaire"
|
||||
? innerUrl || outerUrl
|
||||
: outerUrl || innerUrl;
|
||||
|
||||
if (fileType === "image" && url) {
|
||||
messages.push({
|
||||
type: "image",
|
||||
content: file.URL,
|
||||
name: file.file?.name || file.name || "图片",
|
||||
content: url,
|
||||
name: innerFile?.name || file?.name || "图片",
|
||||
});
|
||||
} else if (file.file.type === "article" && file.file?.url) {
|
||||
// 发送宣教文章 - 从 URL 中解析 id
|
||||
const articleId = extractIdFromUrl(file.file.url);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fileType === "article") {
|
||||
const fallbackArticleId =
|
||||
String(
|
||||
innerFile?._id ||
|
||||
file?._id ||
|
||||
innerFile?.articleId ||
|
||||
file?.articleId ||
|
||||
""
|
||||
) || "";
|
||||
const extractedId = extractIdFromUrl(url);
|
||||
const articleId = String(extractedId || fallbackArticleId || "");
|
||||
|
||||
let articleUrl = String(url || "");
|
||||
if (!articleUrl && articleId) {
|
||||
const corpId = getCorpId();
|
||||
articleUrl = `${__VITE_ENV__?.MP_PATIENT_PAGE_BASE_URL || ""}pages/article/index?id=${encodeURIComponent(
|
||||
articleId
|
||||
)}&corpId=${encodeURIComponent(corpId || "")}`;
|
||||
}
|
||||
|
||||
if (!articleId && !articleUrl) continue;
|
||||
|
||||
messages.push({
|
||||
type: "article",
|
||||
content: {
|
||||
_id: articleId,
|
||||
title: file.file?.name || "宣教文章",
|
||||
url: file.file?.url || file.URL,
|
||||
subtitle: file.file?.subtitle || "",
|
||||
cover: file.file?.cover || "",
|
||||
title: innerFile?.name || file?.name || "宣教文章",
|
||||
url: articleUrl,
|
||||
subtitle: innerFile?.subtitle || "",
|
||||
cover: innerFile?.cover || file?.URL || "",
|
||||
articleId: articleId,
|
||||
},
|
||||
});
|
||||
} else if (
|
||||
file.file.type === "questionnaire" &&
|
||||
(file.file?.url || file.URL)
|
||||
) {
|
||||
// 发送问卷 - 从 URL 中解析 surveryId
|
||||
const surveryUrl = file.file?.url || file.URL;
|
||||
const surveryId = extractSurveryIdFromUrl(surveryUrl);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fileType === "questionnaire") {
|
||||
const surveryId = innerFile?.surveryId || file?.surveryId;
|
||||
if (!surveryId) continue;
|
||||
const surveyId =
|
||||
String(innerFile?._id || file?._id || surveryId || "") || "";
|
||||
messages.push({
|
||||
type: "questionnaire",
|
||||
content: {
|
||||
_id: surveryId,
|
||||
name: file.file?.name || file.name || "问卷",
|
||||
surveryId: surveryId,
|
||||
url: surveryUrl,
|
||||
_id: surveyId,
|
||||
name: innerFile?.name || file?.name || "问卷",
|
||||
surveryId,
|
||||
url: String(url || ""),
|
||||
createBy: innerFile?.createBy,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 调用统一的消息发送处理函数
|
||||
const success = await handleFollowUpMessages(messages, {
|
||||
return messages;
|
||||
}
|
||||
|
||||
async function goChatAndSend(todo) {
|
||||
if (!canShowSendButton(todo)) return;
|
||||
if (!props.archiveId) return;
|
||||
|
||||
let gid = normalizeGroupId(currentChatGroupId.value || "");
|
||||
if (!gid) {
|
||||
await refreshChatRoomByApi();
|
||||
gid = normalizeGroupId(currentChatGroupId.value || "");
|
||||
}
|
||||
if (!gid) {
|
||||
toast("暂无可进入的会话");
|
||||
return;
|
||||
}
|
||||
|
||||
const messages = buildFollowUpMessages(todo);
|
||||
if (!messages.length) {
|
||||
console.warn("[followup] buildFollowUpMessages empty:", {
|
||||
sendContent: todo?.sendContent,
|
||||
fileList: todo?.fileList,
|
||||
});
|
||||
toast("发送内容解析失败");
|
||||
return;
|
||||
}
|
||||
|
||||
const conversationID = `GROUP${gid}`;
|
||||
|
||||
uni.setStorageSync(PENDING_FOLLOWUP_SEND_STORAGE_KEY, {
|
||||
createdAt: Date.now(),
|
||||
groupId: gid,
|
||||
conversationID,
|
||||
messages,
|
||||
context: {
|
||||
userId: getUserId(),
|
||||
customerId: props.archiveId,
|
||||
customerName: props.data?.name || "",
|
||||
corpId: getCorpId(),
|
||||
env: __VITE_ENV__,
|
||||
},
|
||||
});
|
||||
|
||||
if (success) {
|
||||
toast("消息已发送");
|
||||
uni.navigateBack();
|
||||
}
|
||||
} finally {
|
||||
sendingFollowUp.value = false;
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: `/pages/message/index?conversationID=${encodeURIComponent(
|
||||
conversationID
|
||||
)}&groupID=${encodeURIComponent(gid)}&fromCase=true&pendingFollowUpSend=1`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -686,6 +778,83 @@ function extractSurveryIdFromUrl(url) {
|
||||
}
|
||||
}
|
||||
|
||||
const isRefreshingChatRoom = ref(false);
|
||||
let lastRefreshChatRoomAt = 0;
|
||||
|
||||
function parseAnyTimeMs(v) {
|
||||
if (v === null || v === undefined) return 0;
|
||||
if (typeof v === "number") return v;
|
||||
const s = String(v).trim();
|
||||
if (!s) return 0;
|
||||
if (/^\d{10,13}$/.test(s)) return Number(s.length === 10 ? `${s}000` : s);
|
||||
const d = dayjs(s);
|
||||
return d.isValid() ? d.valueOf() : 0;
|
||||
}
|
||||
|
||||
async function refreshChatRoomByApi() {
|
||||
const customerId = String(props.archiveId || "");
|
||||
if (!customerId) return;
|
||||
if (isRefreshingChatRoom.value) return;
|
||||
const now = Date.now();
|
||||
if (now - lastRefreshChatRoomAt < 5000) return;
|
||||
lastRefreshChatRoomAt = now;
|
||||
|
||||
isRefreshingChatRoom.value = true;
|
||||
try {
|
||||
await ensureDoctor();
|
||||
const corpId = getCorpId();
|
||||
const teamId = getCurrentTeamId();
|
||||
|
||||
const baseQuery = {
|
||||
corpId,
|
||||
customerId,
|
||||
page: 1,
|
||||
pageSize: 50,
|
||||
};
|
||||
|
||||
const queryWithTeam = teamId ? { ...baseQuery, teamId } : baseQuery;
|
||||
let detailRes = await api("getGroupList", queryWithTeam, false);
|
||||
let details = Array.isArray(detailRes?.data?.list) ? detailRes.data.list : [];
|
||||
if (!details.length && teamId) {
|
||||
detailRes = await api("getGroupList", baseQuery, false);
|
||||
details = Array.isArray(detailRes?.data?.list) ? detailRes.data.list : [];
|
||||
}
|
||||
|
||||
if (!detailRes?.success || !details.length) {
|
||||
chatGroupId.value = "";
|
||||
return;
|
||||
}
|
||||
|
||||
const currentTeamId = getCurrentTeamId();
|
||||
const detailsForCurrentTeam = currentTeamId
|
||||
? details.filter(
|
||||
(g) =>
|
||||
String(g?.teamId || g?.team?._id || g?.team?.teamId || "") ===
|
||||
currentTeamId
|
||||
)
|
||||
: [];
|
||||
const candidates = detailsForCurrentTeam.length ? detailsForCurrentTeam : details;
|
||||
|
||||
const statusRank = (s) => (s === "processing" ? 3 : s === "pending" ? 2 : 1);
|
||||
candidates.sort((a, b) => {
|
||||
const ra = statusRank(String(a?.orderStatus || ""));
|
||||
const rb = statusRank(String(b?.orderStatus || ""));
|
||||
if (rb !== ra) return rb - ra;
|
||||
const ta = parseAnyTimeMs(a?.updatedAt) || parseAnyTimeMs(a?.createdAt);
|
||||
const tb = parseAnyTimeMs(b?.updatedAt) || parseAnyTimeMs(b?.createdAt);
|
||||
return tb - ta;
|
||||
});
|
||||
|
||||
const best = candidates[0] || {};
|
||||
const gid = normalizeGroupId(best.groupId || best.groupID || best.group_id || "");
|
||||
chatGroupId.value = gid ? String(gid) : "";
|
||||
} catch (e) {
|
||||
// ignore
|
||||
} finally {
|
||||
isRefreshingChatRoom.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- filter popup ----
|
||||
const filterPopupRef = ref(null);
|
||||
const state = ref(null);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user