diff --git a/pages/qunliaotian/qunliaotian.js b/pages/qunliaotian/qunliaotian.js
index 01cf295..12a48f8 100644
--- a/pages/qunliaotian/qunliaotian.js
+++ b/pages/qunliaotian/qunliaotian.js
@@ -3,6 +3,7 @@ import { formatDate } from '../../static/lib/utils';
import { sendGroupMessage } from '../../utils/message-sender';
import { showConfirmByScene } from '../../utils/scriptService.js';
import { normalizeGroupMessage } from '../../utils/group-chat.js';
+import { getFreshImUser } from '../../utils/im-user.js';
Page({
data: {
@@ -62,17 +63,6 @@ Page({
}
},
- // 原有的 initCurrentUser 保留,仅当没有外部参数时使用
- initCurrentUser() {
- const uid = wx.getStorageSync('uid');
- const role = app.globalData.currentRole || 'normal';
- const prefix = { normal:'Boss', dashou:'Ds', shangjia:'Sj', guanshi:'Gs', zuzhang:'Zz' }[role] || 'Boss';
- this.setData({ currentUser: {
- id: prefix + uid,
- name: app.globalData.currentUser?.name || `用户${uid}`,
- avatar: this.fixAvatar(wx.getStorageSync('touxiang'))
- }});
- },
/*onLoad(options) {
if (options.data) {
try {
@@ -184,11 +174,11 @@ Page({
initCurrentUser() {
const uid = wx.getStorageSync('uid');
const role = app.globalData.currentRole || 'normal';
- const prefix = { normal:'Boss', dashou:'Ds', shangjia:'Sj', guanshi:'Gs', zuzhang:'Zz' }[role] || 'Boss';
+ const fresh = getFreshImUser(app, role, uid);
this.setData({ currentUser: {
- id: prefix + uid,
- name: app.globalData.currentUser?.name || `用户${uid}`,
- avatar: this.fixAvatar(wx.getStorageSync('touxiang'))
+ id: fresh.id,
+ name: fresh.name,
+ avatar: fresh.avatar,
}});
},
diff --git a/pages/xiaoxi/xiaoxi.js b/pages/xiaoxi/xiaoxi.js
index 2d70bf2..13a91bf 100644
--- a/pages/xiaoxi/xiaoxi.js
+++ b/pages/xiaoxi/xiaoxi.js
@@ -2,7 +2,8 @@
const app = getApp();
import { formatDate } from '../../static/lib/utils';
const { jianquanxian } = require('../../utils/imAuth/jianquanxian');
-import { enrichGroupConversation, isOrderGroupConversation } from '../../utils/group-chat.js';
+import { enrichGroupConversation, isOrderGroupConversation, sortConversations, recordConversationOpen } from '../../utils/group-chat.js';
+import { loadGroupMetaCache } from '../../utils/im-user.js';
Page({
data: {
@@ -24,10 +25,33 @@ Page({
this.calculateScrollHeight();
const muted = wx.getStorageSync('notificationMuted') || false;
this.setData({ notificationMuted: muted });
+ loadGroupMetaCache(app);
+ this._onGlobalConvUpdated = (result) => {
+ const content = result?.content || result;
+ if (content && content.conversations) {
+ this.renderConversations(content);
+ }
+ };
+ app.on('conversationsUpdated', this._onGlobalConvUpdated);
+ app.on('unreadCountChanged', this._onGlobalConvUpdated);
+ },
+
+ onUnload() {
+ if (this._onGlobalConvUpdated) {
+ app.off('conversationsUpdated', this._onGlobalConvUpdated);
+ app.off('unreadCountChanged', this._onGlobalConvUpdated);
+ }
},
onShow() {
if (!this.checkLoginStatus()) return;
+ loadGroupMetaCache(app);
+ if (app.globalData.messageManager?.unreadTotal != null) {
+ app.emitEvent('tabBarBadgeChanged', {
+ badgeText: app.globalData.messageManager.unreadTotal > 0
+ ? String(app.globalData.messageManager.unreadTotal) : ''
+ });
+ }
this.checkPermissionAndAutoConnect();
},
@@ -194,11 +218,14 @@ Page({
const meta = groupMeta[item.groupId];
if (meta) {
if (!item.data) item.data = {};
- if (meta.name) item.data.name = meta.name;
- if (meta.avatar) item.data.avatar = meta.avatar;
- if (meta.orderDesc) item.data.orderDesc = meta.orderDesc;
- if (meta.orderId) item.data.orderId = meta.orderId;
- if (meta.orderZhuangtai != null) item.data.orderZhuangtai = meta.orderZhuangtai;
+ Object.assign(item.data, meta);
+ }
+ if (item.data && item.data.dashouGoEasyId) {
+ if (!app.globalData.groupInfoMap) app.globalData.groupInfoMap = {};
+ app.globalData.groupInfoMap[item.groupId] = {
+ ...app.globalData.groupInfoMap[item.groupId],
+ ...item.data,
+ };
}
enrichGroupConversation(item, myGoEasyId, defaultAvatar, ossBase);
} else if (item.data && item.data.avatar) {
@@ -213,24 +240,23 @@ Page({
}
});
- 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;
- return (b.lastMessage.timestamp || 0) - (a.lastMessage.timestamp || 0);
- });
+ const openTimes = wx.getStorageSync('conversationOpenTimes') || {};
+ sortConversations(list, openTimes);
+
+ const unreadTotal = content.unreadTotal !== undefined ? content.unreadTotal : list.reduce((sum, c) => sum + (c.unread || 0), 0);
+ if (app.globalData.messageManager) {
+ app.globalData.messageManager.unreadTotal = unreadTotal;
+ }
+ if (app && app.emitEvent) {
+ app.emitEvent('tabBarBadgeChanged', { badgeText: unreadTotal > 0 ? String(unreadTotal) : '' });
+ app.emitEvent('unreadCountChanged', { unreadTotal });
+ }
this.setData({ allConversations: list, displayCount: 4 }, () => {
this.applyFilter();
});
- const unreadTotal = content.unreadTotal !== undefined ? content.unreadTotal : list.reduce((sum, c) => sum + (c.unread || 0), 0);
- if (app && app.emitEvent) {
- app.emitEvent('tabBarBadgeChanged', { badgeText: unreadTotal > 0 ? String(unreadTotal) : '' });
- }
-
- // ✅ 每次渲染会话后,无条件重新订阅所有群组,确保订阅关系始终有效
+ // 群组订阅(不重复断开连接)
this.subscribeGroupsIfNeeded(list);
},
@@ -316,6 +342,7 @@ Page({
chat(e) {
const conversation = e.currentTarget.dataset.conversation;
if (!conversation) return;
+ recordConversationOpen(conversation);
if (conversation.type === 'private') {
const param = {
diff --git a/pages/xiaoxi/xiaoxi.wxml b/pages/xiaoxi/xiaoxi.wxml
index a69a9dd..46e169b 100644
--- a/pages/xiaoxi/xiaoxi.wxml
+++ b/pages/xiaoxi/xiaoxi.wxml
@@ -37,6 +37,15 @@
{{item.lastMessage.date}}
+
+ 对方 {{item.data.counterpartYonghuid}} {{item.data.name}}
+
+
+ 打手 {{item.data.dashouYonghuid}} {{item.data.dashouNicheng}}
+
+
+ {{item.data.partnerRoleLabel || '商家'}} {{item.data.partnerYonghuid}} {{item.data.partnerNicheng}}
+
单号 {{item.data.orderId}}
{{item.data.orderDesc}}
diff --git a/pages/xiaoxi/xiaoxi.wxss b/pages/xiaoxi/xiaoxi.wxss
index 3d1ca42..c43c4f1 100644
--- a/pages/xiaoxi/xiaoxi.wxss
+++ b/pages/xiaoxi/xiaoxi.wxss
@@ -23,6 +23,9 @@
.top-line { display: flex; justify-content: space-between; margin-bottom: 8rpx; }
.name { font-size: 30rpx; color: #1a1a1a; font-weight: 500; }
.time { font-size: 22rpx; color: #999; flex-shrink: 0; margin-left: 12rpx; }
+.user-meta-row { margin-bottom: 4rpx; }
+.user-meta { font-size: 24rpx; color: #333; }
+.user-meta.sub { color: #666; font-size: 22rpx; }
.order-block { background: #f7f8fa; border-radius: 12rpx; padding: 16rpx 18rpx; margin-bottom: 10rpx; }
.order-id { display: block; font-size: 24rpx; color: #576b95; margin-bottom: 6rpx; }
.order-desc { display: block; font-size: 26rpx; color: #333; line-height: 1.5; word-break: break-all; }
diff --git a/utils/chat-core.js b/utils/chat-core.js
index d3bc751..20f5265 100644
--- a/utils/chat-core.js
+++ b/utils/chat-core.js
@@ -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();
diff --git a/utils/group-chat.js b/utils/group-chat.js
index 9410394..dc81e6b 100644
--- a/utils/group-chat.js
+++ b/utils/group-chat.js
@@ -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) {}
+}
diff --git a/utils/im-user.js b/utils/im-user.js
new file mode 100644
index 0000000..2ea6b63
--- /dev/null
+++ b/utils/im-user.js
@@ -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) {}
+}
diff --git a/utils/message-sender.js b/utils/message-sender.js
index 879ee25..be84948 100644
--- a/utils/message-sender.js
+++ b/utils/message-sender.js
@@ -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
diff --git a/utils/xiaoxilj.js b/utils/xiaoxilj.js
index 72cff09..2e65348 100644
--- a/utils/xiaoxilj.js
+++ b/utils/xiaoxilj.js
@@ -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({