539 lines
15 KiB
JavaScript
539 lines
15 KiB
JavaScript
const request = require('../../api/request.js');
|
||
|
||
const uploadFile = require('../../api/upload.js');
|
||
Page({
|
||
data: {
|
||
messages: [],
|
||
inputText: '',
|
||
scrollToId: '',
|
||
userAvatar: '/static/user.png',
|
||
serviceAvatar: '/static/contact.png',
|
||
showGetUser: false,
|
||
userInfo: {},
|
||
appid: '',
|
||
page: 1,
|
||
page_size: 100,
|
||
openid: '',
|
||
total: 0,
|
||
isAtBottom: true,
|
||
loadingMore: false,
|
||
showNewMessageTip: false,
|
||
newMessageCount: 0,
|
||
lastMessageId: '',
|
||
hasWelcomeMessageSent: false,
|
||
},
|
||
onLoad(options) {
|
||
const accountInfo = wx.getAccountInfoSync();
|
||
this.setData({
|
||
appid: accountInfo.miniProgram.appId,
|
||
});
|
||
|
||
if (wx.getStorageSync('user_info')) {
|
||
this.setData({
|
||
showGetUser: false,
|
||
userInfo: wx.getStorageSync('user_info'),
|
||
});
|
||
this.getMessages().then(() => {
|
||
this.sendWelcomeMessage();
|
||
});
|
||
this.startPolling();
|
||
} else {
|
||
this.silentLogin();
|
||
}
|
||
},
|
||
|
||
getMessages() {
|
||
const userInfo = wx.getStorageSync('user_info');
|
||
const that = this;
|
||
return request('app/messages', 'get', {
|
||
app_id: that.data.appid,
|
||
user_id: userInfo.openid,
|
||
page: that.data.page,
|
||
page_size: that.data.page_size,
|
||
}).then(res => {
|
||
const list = that.processMessages(res.list);
|
||
|
||
const sortedList = that.sortMessagesByID(list);
|
||
|
||
const updateData = {
|
||
messages: sortedList,
|
||
total: res.total
|
||
};
|
||
|
||
that.setData(updateData);
|
||
|
||
if (that.data.isAtBottom && sortedList.length > 0) {
|
||
const lastMessageId = sortedList[sortedList.length - 1].id;
|
||
console.log('用户在底部,准备自动滚动到消息ID:', lastMessageId);
|
||
setTimeout(() => {
|
||
that.setData({
|
||
scrollToId: lastMessageId
|
||
});
|
||
console.log('已设置scrollToId:', lastMessageId);
|
||
}, 50);
|
||
} else {
|
||
console.log('用户不在底部或无消息,保持当前位置。isAtBottom:', that.data.isAtBottom, '消息数量:', sortedList.length);
|
||
}
|
||
|
||
return res;
|
||
});
|
||
},
|
||
|
||
loadMoreAtTop() {
|
||
if (this.data.loadingMore) return;
|
||
const already = this.data.messages.length || 0;
|
||
if (already >= this.data.total) return;
|
||
|
||
const nextPage = this.data.page + 1;
|
||
this.setData({ loadingMore: true });
|
||
|
||
const userInfo = wx.getStorageSync('user_info');
|
||
const that = this;
|
||
|
||
const prevTopId = this.data.messages[0] ? this.data.messages[0].id : null;
|
||
|
||
request('app/messages', 'get', {
|
||
app_id: this.data.appid,
|
||
user_id: userInfo.openid,
|
||
page: nextPage,
|
||
page_size: this.data.page_size,
|
||
}).then(res => {
|
||
const newList = that.processMessages(res.list);
|
||
|
||
const combined = newList.concat(that.data.messages);
|
||
|
||
const sortedCombined = that.sortMessagesByID(combined);
|
||
|
||
that.setData({
|
||
messages: sortedCombined,
|
||
page: nextPage,
|
||
total: res.total,
|
||
}, () => {
|
||
if (prevTopId) {
|
||
that.setData({ scrollToId: prevTopId });
|
||
}
|
||
that.setData({ loadingMore: false });
|
||
});
|
||
}).catch(() => {
|
||
that.setData({ loadingMore: false });
|
||
});
|
||
},
|
||
processMessages(messageList) {
|
||
const processedMessages = messageList.map((item, index) => {
|
||
if (item.id && !item.id.toString().startsWith('m') && !item.id.toString().startsWith('u')) {
|
||
item.id = 'm' + item.id;
|
||
} else if (item.create_time) {
|
||
item.id = 'm' + new Date(item.create_time).getTime();
|
||
} else if (!item.id) {
|
||
item.id = 'm' + (Date.now() + index);
|
||
}
|
||
|
||
if (typeof item.content === 'string') {
|
||
try {
|
||
item.content = {
|
||
message: JSON.parse(item.content).message || JSON.parse(item.content).messages
|
||
}
|
||
} catch (e) {
|
||
console.warn('消息内容解析失败:', item.content);
|
||
item.content = { message: item.content };
|
||
}
|
||
}
|
||
|
||
return item;
|
||
});
|
||
|
||
this.checkNewMessages(processedMessages);
|
||
|
||
return processedMessages;
|
||
},
|
||
checkNewMessages(newMessages) {
|
||
if (newMessages.length === 0) return;
|
||
|
||
const currentMessages = this.data.messages;
|
||
const currentLastMessageId = this.data.lastMessageId;
|
||
const sortedNewMessages = this.sortMessagesByID(newMessages);
|
||
const latestNewMessage = sortedNewMessages[sortedNewMessages.length - 1];
|
||
if (!this.data.isAtBottom && currentMessages.length > 0) {
|
||
const currentMessageIds = new Set(currentMessages.map(msg => msg.id));
|
||
const realNewMessages = sortedNewMessages.filter(msg => !currentMessageIds.has(msg.id));
|
||
|
||
if (realNewMessages.length > 0) {
|
||
const currentCount = this.data.newMessageCount || 0;
|
||
this.setData({
|
||
showNewMessageTip: true,
|
||
newMessageCount: currentCount + realNewMessages.length
|
||
});
|
||
}
|
||
}
|
||
if (latestNewMessage) {
|
||
this.setData({
|
||
lastMessageId: latestNewMessage.id
|
||
});
|
||
}
|
||
},
|
||
sortMessagesByID(messages) {
|
||
return messages.sort((a, b) => {
|
||
const getNumericId = (id) => {
|
||
if (id.startsWith('u')) {
|
||
return parseInt(id.replace('u', '')) || 0;
|
||
} else if (id.startsWith('m')) {
|
||
const numId = parseInt(id.replace('m', '')) || 0;
|
||
if (numId < 1000000000000) {
|
||
return numId + 1000000000;
|
||
}
|
||
return numId;
|
||
}
|
||
return 0;
|
||
};
|
||
|
||
const idA = getNumericId(a.id);
|
||
const idB = getNumericId(b.id);
|
||
return idA - idB;
|
||
});
|
||
},
|
||
silentLogin() {
|
||
const that = this;
|
||
const accountInfo = wx.getAccountInfoSync();
|
||
wx.login({
|
||
success: function (res) {
|
||
request('wechat/miniprogram/login', 'post', {
|
||
"app_id": accountInfo.miniProgram.appId,
|
||
"js_code": res.code
|
||
}).then(resp => {
|
||
wx.setStorageSync('user_info', resp);
|
||
that.setData({
|
||
showGetUser: false,
|
||
userInfo: resp
|
||
});
|
||
request('app/user/create', 'post', {
|
||
"app_id": accountInfo.miniProgram.appId,
|
||
"user_avatar": resp.user_avatar || '/static/user.png',
|
||
"user_id": resp.openid,
|
||
"user_name": resp.user_name || '微信用户'
|
||
}).then(resp => {
|
||
that.getMessages().then(() => {
|
||
that.sendWelcomeMessage();
|
||
});
|
||
that.startPolling();
|
||
});
|
||
}).catch(err => {
|
||
console.error('静默登录失败:', err);
|
||
that.setData({
|
||
showGetUser: true
|
||
});
|
||
});
|
||
},
|
||
fail: function (err) {
|
||
console.error('wx.login失败:', err);
|
||
}
|
||
});
|
||
},
|
||
startPolling() {
|
||
if (this.poller) return;
|
||
this.getMessages();
|
||
this.poller = setInterval(() => {
|
||
this.getMessages();
|
||
}, 1000);
|
||
},
|
||
stopPolling() {
|
||
if (this.poller) {
|
||
clearInterval(this.poller);
|
||
this.poller = null;
|
||
}
|
||
},
|
||
onScroll(e) {
|
||
const scrollTop = e.detail.scrollTop || 0;
|
||
const last = this._lastScrollTop || 0;
|
||
if (scrollTop < last) {
|
||
if (this.data.isAtBottom) {
|
||
console.log('用户向上滚动,设置isAtBottom为false');
|
||
this.setData({ isAtBottom: false });
|
||
}
|
||
}
|
||
if (scrollTop <= 2) {
|
||
if (!this.data.loadingMore && this.data.messages.length < this.data.total) {
|
||
this.loadMoreAtTop();
|
||
}
|
||
}
|
||
this._lastScrollTop = scrollTop;
|
||
},
|
||
|
||
onScrollToLower() {
|
||
console.log('用户滚动到底部,当前isAtBottom状态:', this.data.isAtBottom);
|
||
if (!this.data.isAtBottom) {
|
||
this.setData({
|
||
isAtBottom: true,
|
||
showNewMessageTip: false,
|
||
newMessageCount: 0
|
||
});
|
||
console.log('已设置isAtBottom为true');
|
||
this.startPolling();
|
||
const lastId = this.data.messages[this.data.messages.length - 1] ? this.data.messages[this.data.messages.length - 1].id : '';
|
||
if (lastId) {
|
||
this.setData({ scrollToId: lastId });
|
||
console.log('设置scrollToId到最新消息:', lastId);
|
||
}
|
||
} else {
|
||
if (this.data.showNewMessageTip) {
|
||
this.setData({
|
||
showNewMessageTip: false,
|
||
newMessageCount: 0
|
||
});
|
||
console.log('隐藏新消息提醒');
|
||
}
|
||
}
|
||
},
|
||
onReady() {
|
||
const now = new Date();
|
||
const timeStr = this.formatTime(now);
|
||
this.setData({
|
||
messages: [],
|
||
scrollToId: 'm1'
|
||
});
|
||
},
|
||
|
||
onInput(e) {
|
||
this.setData({
|
||
inputText: e.detail.value
|
||
});
|
||
},
|
||
sendWelcomeMessage() {
|
||
if (!this.data.userInfo || !this.data.userInfo.openid) {
|
||
console.log('用户信息不存在,无法发送欢迎消息');
|
||
return;
|
||
}
|
||
|
||
const welcomeKey = `welcome_sent_${this.data.userInfo.openid}`;
|
||
const hasWelcomeSent = wx.getStorageSync(welcomeKey);
|
||
|
||
if (hasWelcomeSent) {
|
||
console.log('该用户的欢迎消息已发送过,跳过');
|
||
this.setData({ hasWelcomeMessageSent: true });
|
||
return;
|
||
}
|
||
|
||
const welcomeText = '你好';
|
||
const now = new Date();
|
||
const id = 'welcome_' + Date.now();
|
||
|
||
const msg = {
|
||
id,
|
||
content: {
|
||
message: welcomeText
|
||
},
|
||
"msg_type": 1,
|
||
receiver_id: '',
|
||
send_time: "刚刚",
|
||
sender_id: this.data.userInfo.openid,
|
||
sender_name: this.data.userInfo.user_name
|
||
};
|
||
|
||
// 添加新消息并重新排序
|
||
const newMessages = this.data.messages.concat(msg);
|
||
const sortedMessages = this.sortMessagesByID(newMessages);
|
||
|
||
this.setData({
|
||
messages: sortedMessages,
|
||
hasWelcomeMessageSent: true
|
||
});
|
||
|
||
const accountInfo = wx.getAccountInfoSync();
|
||
const userInfo = wx.getStorageSync('user_info');
|
||
|
||
console.log('发送欢迎消息:', welcomeText);
|
||
|
||
// 发送到服务器
|
||
request('app/send_message', 'POST', {
|
||
"app_id": accountInfo.miniProgram.appId,
|
||
"content": JSON.stringify({
|
||
message: welcomeText
|
||
}),
|
||
"from_user_id": userInfo.openid,
|
||
"from_user_name": userInfo.user_name,
|
||
"msg_type": 1
|
||
}).then(() => {
|
||
console.log('欢迎消息发送成功');
|
||
wx.setStorageSync(welcomeKey, true);
|
||
}).catch(err => {
|
||
console.error('欢迎消息发送失败:', err);
|
||
});
|
||
|
||
setTimeout(() => {
|
||
const latestMessage = sortedMessages[sortedMessages.length - 1];
|
||
this.setData({
|
||
scrollToId: latestMessage ? latestMessage.id : id
|
||
});
|
||
}, 50);
|
||
},
|
||
|
||
sendText() {
|
||
const text = this.data.inputText && this.data.inputText.trim();
|
||
if (!text) return;
|
||
const now = new Date();
|
||
const id = 'u' + Date.now();
|
||
const msg = {
|
||
id,
|
||
content: {
|
||
message: text
|
||
},
|
||
"msg_type": 1,
|
||
receiver_id: '',
|
||
send_time: "刚刚",
|
||
sender_id: this.data.userInfo.openid,
|
||
sender_name: this.data.userInfo.user_name
|
||
};
|
||
|
||
const newMessages = this.data.messages.concat(msg);
|
||
const sortedMessages = this.sortMessagesByID(newMessages);
|
||
|
||
this.setData({
|
||
messages: sortedMessages,
|
||
inputText: ''
|
||
});
|
||
const accountInfo = wx.getAccountInfoSync();
|
||
const userInfo = wx.getStorageSync('user_info')
|
||
request('app/send_message', 'POST', {
|
||
"app_id": accountInfo.miniProgram.appId,
|
||
"content": JSON.stringify({
|
||
message: text
|
||
}),
|
||
"from_user_id": userInfo.openid,
|
||
"from_user_name": userInfo.user_name,
|
||
"msg_type": 1
|
||
})
|
||
setTimeout(() => {
|
||
const latestMessage = sortedMessages[sortedMessages.length - 1];
|
||
this.setData({
|
||
scrollToId: latestMessage ? latestMessage.id : id
|
||
});
|
||
}, 50);
|
||
},
|
||
|
||
chooseImage() {
|
||
const that = this;
|
||
wx.chooseImage({
|
||
count: 1,
|
||
mediaType: ['image'],
|
||
sizeType: ['compressed', 'original'],
|
||
sourceType: ['album', 'camera'],
|
||
success(res) {
|
||
const tempFilePaths = res.tempFilePaths;
|
||
console.log('选择的图片路径:', res);
|
||
if (tempFilePaths && tempFilePaths.length) {
|
||
const userInfo = wx.getStorageSync('user_info')
|
||
const id = 'u' + Date.now();
|
||
const msg = {
|
||
id,
|
||
msg_type: '2',
|
||
receiver_id: '',
|
||
content: {
|
||
message: tempFilePaths[0]
|
||
},
|
||
sender_id: userInfo.openid,
|
||
sender_name: userInfo.user_name,
|
||
receiver_id: '',
|
||
send_time: "刚刚",
|
||
};
|
||
const list = that.data.messages
|
||
list.push(msg);
|
||
that.setData({
|
||
messages: list
|
||
});
|
||
setTimeout(() => {
|
||
that.setData({
|
||
scrollToId: id
|
||
});
|
||
}, 50);
|
||
uploadFile(tempFilePaths[0]).then((res) => {
|
||
|
||
const accountInfo = wx.getAccountInfoSync();
|
||
|
||
request('app/send_message', 'POST', {
|
||
"app_id": accountInfo.miniProgram.appId,
|
||
"content": JSON.stringify({
|
||
message: res
|
||
}),
|
||
"from_user_id": userInfo.openid,
|
||
"from_user_name": userInfo.user_name,
|
||
"msg_type": 2
|
||
}).catch((err) => {
|
||
wx.showToast({
|
||
title: '图片发送失败',
|
||
icon: 'none'
|
||
});
|
||
});
|
||
}).catch((err) => {
|
||
wx.showToast({
|
||
title: '图片发送失败',
|
||
icon: 'none'
|
||
});
|
||
});
|
||
}
|
||
}
|
||
});
|
||
},
|
||
formatTime(date) {
|
||
const y = date.getFullYear();
|
||
const m = (date.getMonth() + 1).toString().padStart(2, '0');
|
||
const d = date.getDate().toString().padStart(2, '0');
|
||
const h = date.getHours().toString().padStart(2, '0');
|
||
const min = date.getMinutes().toString().padStart(2, '0');
|
||
return `${y}年${m}月${d}日 ${h}:${min}`;
|
||
},
|
||
|
||
previewImage(e) {
|
||
const src = e.currentTarget.dataset.src;
|
||
if (!src) return;
|
||
wx.previewImage({
|
||
urls: [src],
|
||
current: src
|
||
});
|
||
},
|
||
|
||
onShow() {
|
||
if (wx.getStorageSync('user_info')) {
|
||
this.getMessages();
|
||
this.startPolling();
|
||
}
|
||
},
|
||
onHide() {
|
||
this.stopPolling();
|
||
},
|
||
onUnload() {
|
||
this.stopPolling();
|
||
},
|
||
onPullDownRefresh() {
|
||
if (wx.getStorageSync('user_info')) {
|
||
this.getMessages().then(() => {
|
||
wx.stopPullDownRefresh();
|
||
}).catch(() => {
|
||
wx.stopPullDownRefresh();
|
||
});
|
||
} else {
|
||
wx.stopPullDownRefresh();
|
||
}
|
||
},
|
||
scrollToBottom() {
|
||
const messages = this.data.messages;
|
||
if (messages.length > 0) {
|
||
const sortedMessages = this.sortMessagesByID(messages);
|
||
const latestMessage = sortedMessages[sortedMessages.length - 1];
|
||
|
||
this.setData({
|
||
scrollToId: latestMessage.id,
|
||
showNewMessageTip: false,
|
||
newMessageCount: 0,
|
||
isAtBottom: true
|
||
});
|
||
|
||
setTimeout(() => {
|
||
this.setData({
|
||
scrollToId: ''
|
||
});
|
||
}, 100);
|
||
}
|
||
},
|
||
|
||
onReachBottom() { },
|
||
onShareAppMessage() { }
|
||
}); |