同步聊天修复到根目录pages/utils(与副本工程结构一致)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-06-23 23:30:14 +08:00
parent 033359f6f4
commit 7b3e7a39e9
9 changed files with 258 additions and 65 deletions

View File

@@ -1,6 +1,7 @@
// utils/chat-core.js
import GoEasy from '../static/lib/goeasy-2.13.24.esm.min';
import { jianquanxian } from './imAuth/jianquanxian';
import { getFreshImUser } from './im-user.js';
let _globalPrivateHandler = null;
let _globalGroupHandler = null;
@@ -209,16 +210,22 @@ async function connectWithIdentity(app, identityType, userId, isAutoRestore = fa
saveConnectionState(app);
const uid = wx.getStorageSync('uid');
const role = app.globalData.currentRole || identityType || 'normal';
const freshUser = getFreshImUser(app, role, uid);
const currentUser = app.globalData.currentUser || {
id: uid,
name: '用户' + (uid ? uid.substring(0, 6) : ''),
avatar: app.globalData.ossImageUrl + app.globalData.morentouxiang,
name: freshUser.name,
avatar: freshUser.avatar,
};
return new Promise((resolve, reject) => {
wx.goEasy.connect({
id: userId,
data: { name: currentUser.name, avatar: currentUser.avatar, identityType },
data: {
name: freshUser.name || currentUser.name,
avatar: freshUser.avatar || currentUser.avatar || (app.globalData.ossImageUrl + app.globalData.morentouxiang),
identityType,
},
onSuccess: () => {
app.globalData.goEasyConnection.status = 'connected';
app.globalData.goEasyConnection.lastConnectTime = Date.now();

View File

@@ -1,5 +1,5 @@
/**
* 打手-商家/老板配对群group_Ds{打手}_Sj{商家} 或 group_Ds{打手}_Boss{老板}
* 打手-商家/老板配对群group_Ds{打手}_Sj{商家}
*/
export const ORDER_CARD_PREFIX = '[ORDER_CARD]';
@@ -29,6 +29,67 @@ export function getCounterpartGoEasyId(groupId, myGoEasyId) {
return null;
}
function fixAvatarUrl(avatar, defaultAvatar, ossBase) {
if (!avatar) return defaultAvatar;
if (avatar.startsWith('http')) return avatar;
return (ossBase || '') + avatar.replace(/^\//, '');
}
/** 根据群 to.data 与当前身份,解析对方/双方展示信息 */
export function applyPairMetaToConversation(item, myGoEasyId, defaultAvatar, ossBase) {
if (!item || !item.data) return;
const d = item.data;
if (d.dashouGoEasyId && d.partnerGoEasyId) {
const isDashou = myGoEasyId === d.dashouGoEasyId;
const isPartner = myGoEasyId === d.partnerGoEasyId;
d.dashouNicheng = d.dashouName || d.dashouNicheng || '';
d.partnerNicheng = d.partnerName || d.partnerNicheng || '';
d.dashouAvatar = fixAvatarUrl(d.dashouAvatar, defaultAvatar, ossBase);
d.partnerAvatar = fixAvatarUrl(d.partnerAvatar, defaultAvatar, ossBase);
if (isDashou) {
d.counterpartId = d.partnerGoEasyId;
d.counterpartYonghuid = d.partnerYonghuid || d.partnerGoEasyId.replace(/^(Sj|Boss)/, '');
d.partnerRoleLabel = d.partnerGoEasyId.startsWith('Boss') ? '老板' : '商家';
d.name = d.partnerNicheng || `${d.partnerRoleLabel}${d.counterpartYonghuid}`;
d.avatar = d.partnerAvatar || defaultAvatar;
} else if (isPartner) {
d.counterpartId = d.dashouGoEasyId;
d.counterpartYonghuid = d.dashouYonghuid || d.dashouGoEasyId.replace(/^Ds/, '');
d.name = d.dashouNicheng || `打手${d.counterpartYonghuid}`;
d.avatar = d.dashouAvatar || defaultAvatar;
} else {
const cpId = getCounterpartGoEasyId(item.groupId, myGoEasyId);
if (cpId === d.partnerGoEasyId) {
d.name = d.partnerNicheng;
d.avatar = d.partnerAvatar || defaultAvatar;
} else if (cpId === d.dashouGoEasyId) {
d.name = d.dashouNicheng;
d.avatar = d.dashouAvatar || defaultAvatar;
}
}
return;
}
const counterpartId = getCounterpartGoEasyId(item.groupId, myGoEasyId);
if (counterpartId) {
d.counterpartId = counterpartId;
d.counterpartYonghuid = counterpartId.replace(/^(Ds|Sj|Boss)/, '');
if (!d.name || d.name === item.groupId) {
d.name = `用户${d.counterpartYonghuid.slice(-6)}`;
}
}
if (item.lastMessage && item.lastMessage.senderId && item.lastMessage.senderId !== myGoEasyId) {
const sd = item.lastMessage.senderData || {};
if (sd.avatar) d.avatar = fixAvatarUrl(sd.avatar, defaultAvatar, ossBase);
if (sd.name) d.name = sd.name;
}
d.avatar = fixAvatarUrl(d.avatar, defaultAvatar, ossBase);
}
export function parseOrderCardText(text) {
if (!text || !text.startsWith(ORDER_CARD_PREFIX)) return null;
try {
@@ -77,36 +138,49 @@ export function enrichGroupConversation(item, myGoEasyId, defaultAvatar, ossBase
if (!item || item.type !== 'group') return item;
if (!item.data) item.data = {};
const counterpartId = getCounterpartGoEasyId(item.groupId, myGoEasyId);
if (counterpartId) {
item.data.counterpartId = counterpartId;
if (!item.data.name || item.data.name === item.groupId) {
item.data.name = `用户${counterpartId.replace(/^(Ds|Sj|Boss)/, '').slice(-6)}`;
}
}
if (item.lastMessage && item.lastMessage.senderId && item.lastMessage.senderId !== myGoEasyId) {
const sd = item.lastMessage.senderData || {};
if (sd.avatar) item.data.avatar = sd.avatar;
if (sd.name) item.data.name = sd.name;
}
let avatar = item.data.avatar || '';
if (avatar && !avatar.startsWith('http')) {
avatar = (ossBase || '') + avatar.replace(/^\//, '');
}
item.data.avatar = avatar || defaultAvatar;
applyPairMetaToConversation(item, myGoEasyId, defaultAvatar, ossBase);
if (item.data.orderZhuangtai != null) {
item.data.orderZhuangtaiText = ZHUANGTAI_MAP[item.data.orderZhuangtai] || '';
}
item.displayLastMsg = formatLastMessagePreview(item.lastMessage);
if (!item.data.avatar) item.data.avatar = defaultAvatar;
return item;
}
export function isOrderGroupConversation(c) {
if (!c || c.type !== 'group') return false;
if (c.data && c.data.orderId) return true;
if (c.data && c.data.dashouGoEasyId) return true;
return isPairGroupId(c.groupId) || /^group_\w+$/.test(c.groupId || '');
}
export function getConversationSortTime(conversation, openTimes) {
const id = conversation.groupId || conversation.userId || '';
const msgTs = conversation.lastMessage?.timestamp || 0;
const openTs = (openTimes && id && openTimes[id]) ? openTimes[id] : 0;
return Math.max(msgTs, openTs);
}
export function sortConversations(list, openTimes) {
return list.sort((a, b) => {
if (a.top && !b.top) return -1;
if (!a.top && b.top) return 1;
if (a.unread > 0 && b.unread <= 0) return -1;
if (a.unread <= 0 && b.unread > 0) return 1;
const ta = getConversationSortTime(a, openTimes);
const tb = getConversationSortTime(b, openTimes);
return tb - ta;
});
}
export function recordConversationOpen(conversation) {
const id = conversation?.groupId || conversation?.userId;
if (!id) return;
try {
const times = wx.getStorageSync('conversationOpenTimes') || {};
times[id] = Date.now();
wx.setStorageSync('conversationOpenTimes', times);
} catch (e) {}
}

50
utils/im-user.js Normal file
View File

@@ -0,0 +1,50 @@
/**
* IM 用户展示:从本地缓存读取最新头像,空则用默认图
*/
export function getDefaultAvatar(app) {
const oss = app.globalData.ossImageUrl || '';
return oss + (app.globalData.morentouxiang || '');
}
export function resolveAvatarUrl(raw, app) {
const def = getDefaultAvatar(app);
if (!raw) return def;
if (raw.startsWith('http')) return raw;
const oss = app.globalData.ossImageUrl || '';
return oss + raw.replace(/^\//, '');
}
export function getFreshImUser(app, role, uid) {
const prefixMap = {
normal: 'Boss', dashou: 'Ds', shangjia: 'Sj',
guanshi: 'Gs', zuzhang: 'Zz', kaoheguan: 'Kh',
};
const prefix = prefixMap[role] || 'Boss';
const touxiang = wx.getStorageSync('touxiang') || '';
const avatar = resolveAvatarUrl(touxiang, app);
const name = app.globalData.currentUser?.name || `用户${(uid || '').slice(-6)}`;
return {
id: prefix + uid,
name,
avatar,
};
}
export function persistGroupMeta(app, groupId, meta) {
if (!groupId || !meta) return;
if (!app.globalData.groupInfoMap) app.globalData.groupInfoMap = {};
app.globalData.groupInfoMap[groupId] = { ...app.globalData.groupInfoMap[groupId], ...meta };
try {
const cache = wx.getStorageSync('pairGroupMetaCache') || {};
cache[groupId] = app.globalData.groupInfoMap[groupId];
wx.setStorageSync('pairGroupMetaCache', cache);
} catch (e) {}
}
export function loadGroupMetaCache(app) {
try {
const cache = wx.getStorageSync('pairGroupMetaCache') || {};
if (!app.globalData.groupInfoMap) app.globalData.groupInfoMap = {};
Object.assign(app.globalData.groupInfoMap, cache);
} catch (e) {}
}

View File

@@ -2,9 +2,19 @@
const app = getApp();
import { formatDate } from '../static/lib/utils';
import request from './request.js';
import { getFreshImUser } from './im-user.js';
function sendGroupMessage(options) {
const { msgData, onSuccess, onSendStart } = options;
const role = app.globalData.currentRole || 'normal';
const uid = wx.getStorageSync('uid');
const freshUser = getFreshImUser(app, role, uid);
msgData.currentUser = {
...msgData.currentUser,
name: freshUser.name,
avatar: freshUser.avatar,
};
const { type, currentUser, groupId, orderId, isCross, groupName, groupAvatar } = msgData;
const localMsg = buildLocalMessage(msgData);
@@ -41,12 +51,22 @@ function buildLocalMessage(data) {
}
function sendViaSDK(localMsg, currentUser, groupId, onSuccess, orderId, isCross, groupName, groupAvatar) {
const groupMeta = (app.globalData.groupInfoMap && app.globalData.groupInfoMap[groupId]) || {};
const toData = {
name: groupName || '订单群聊',
avatar: groupAvatar || currentUser.avatar
name: groupName || groupMeta.name || '订单群聊',
avatar: groupAvatar || groupMeta.avatar || currentUser.avatar,
orderId: orderId || groupMeta.orderId,
isCross: isCross || 0,
dashouGoEasyId: groupMeta.dashouGoEasyId,
partnerGoEasyId: groupMeta.partnerGoEasyId,
dashouYonghuid: groupMeta.dashouYonghuid,
partnerYonghuid: groupMeta.partnerYonghuid,
dashouName: groupMeta.dashouName,
partnerName: groupMeta.partnerName,
dashouAvatar: groupMeta.dashouAvatar,
partnerAvatar: groupMeta.partnerAvatar,
orderDesc: groupMeta.orderDesc,
};
if (orderId) toData.orderId = orderId;
toData.isCross = isCross || 0;
const to = {
type: wx.GoEasy.IM_SCENE.GROUP,
@@ -80,14 +100,14 @@ function sendViaBackend(localMsg, currentUser, groupId, orderId, onSuccess) {
const identityType = role === 'dashou' ? 'dashou' : (role === 'shangjia' ? 'shangjia' : 'boss');
const prefix = prefixMap[role] || 'Boss';
const senderId = prefix + uid;
const freshUser = getFreshImUser(app, role, uid);
const params = {
orderId: orderId,
groupId: groupId,
identityType: identityType, // 告诉后端当前是什么身份
senderId: senderId,
senderName: currentUser.name || ('用户' + uid),
senderAvatar: currentUser.avatar || (app.globalData.ossImageUrl + app.globalData.morentouxiang),
senderName: freshUser.name || currentUser.name || ('用户' + uid),
senderAvatar: freshUser.avatar || currentUser.avatar || (app.globalData.ossImageUrl + app.globalData.morentouxiang),
messageType: localMsg.type,
messageId: localMsg.messageId,
timestamp: localMsg.timestamp

View File

@@ -2,6 +2,7 @@
* 连接管理模块 - 订单群聊跳转(后端准备群 + 稳定连接)
*/
import request from './request';
import { persistGroupMeta } from './im-user.js';
const app = getApp();
function waitForConnection(expectedUserId, timeout = 15000) {
@@ -127,13 +128,25 @@ class ConnectionManager {
}
if (!app.globalData.groupInfoMap) app.globalData.groupInfoMap = {};
app.globalData.groupInfoMap[realGroupId] = {
const meta = {
name: chatData.counterpartName || chatData.groupName || groupName,
avatar,
orderId: chatData.orderId || orderId,
orderDesc: chatData.orderDesc || '',
orderZhuangtai: chatData.orderZhuangtai,
dashouGoEasyId: chatData.dashouGoEasyId,
partnerGoEasyId: chatData.partnerGoEasyId,
dashouYonghuid: chatData.dashouYonghuid,
partnerYonghuid: chatData.partnerYonghuid,
dashouName: chatData.dashouName,
partnerName: chatData.partnerName,
dashouAvatar: chatData.dashouAvatar,
partnerAvatar: chatData.partnerAvatar,
counterpartId: chatData.counterpartId,
counterpartYonghuid: chatData.counterpartYonghuid,
};
app.globalData.groupInfoMap[realGroupId] = meta;
persistGroupMeta(app, realGroupId, meta);
await new Promise((resolve, reject) => {
wx.goEasy.im.subscribeGroup({