439 lines
13 KiB
JavaScript
439 lines
13 KiB
JavaScript
// pages/contact/index.js
|
||
const request = require('../../api/request.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,
|
||
},
|
||
|
||
/**
|
||
* 生命周期函数--监听页面加载
|
||
*/
|
||
onLoad(options) {
|
||
const accountInfo = wx.getAccountInfoSync();
|
||
console.log(accountInfo.miniProgram);
|
||
this.setData({
|
||
appid: accountInfo.miniProgram.appId,
|
||
});
|
||
console.log('contact page onLoad, options:', options);
|
||
|
||
// 检查是否已有用户信息
|
||
if (wx.getStorageSync('user_info')) {
|
||
this.setData({
|
||
showGetUser: false,
|
||
userInfo: wx.getStorageSync('user_info'),
|
||
});
|
||
this.getMessages()
|
||
// start polling when page loads and user is present
|
||
this.startPolling();
|
||
} else {
|
||
// 直接进行静默登录,不显示授权弹窗
|
||
this.silentLogin();
|
||
}
|
||
},
|
||
// onShow() {
|
||
// this.getMessages()
|
||
// },
|
||
|
||
getMessages() {
|
||
const userInfo = wx.getStorageSync('user_info');
|
||
const that = this;
|
||
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 => {
|
||
console.log('res', res);
|
||
// generate stable ids across pages so we can prepend without collisions
|
||
const base = (that.data.page - 1) * that.data.page_size;
|
||
const list = res.list.map((item, index) => {
|
||
item.id = 'm' + (base + index);
|
||
item.content = JSON.parse(item.content);
|
||
return item;
|
||
});
|
||
that.setData({
|
||
messages: list,
|
||
total: res.total,
|
||
// only auto-scroll if user is at bottom
|
||
scrollToId: that.data.isAtBottom ? (list[list.length - 1] ? list[list.length - 1].id : '') : that.data.scrollToId
|
||
});
|
||
console.log('messages', list);
|
||
})
|
||
},
|
||
|
||
// Load older messages (previous pages) and prepend them to the top
|
||
loadMoreAtTop() {
|
||
if (this.data.loadingMore) return;
|
||
// if we've loaded all messages, skip
|
||
const already = this.data.messages.length || 0;
|
||
if (already >= this.data.total) return;
|
||
|
||
// compute next page to fetch
|
||
const nextPage = this.data.page + 1;
|
||
this.setData({ loadingMore: true });
|
||
|
||
const userInfo = wx.getStorageSync('user_info');
|
||
const that = this;
|
||
|
||
// capture current top-most visible message id to preserve scroll position
|
||
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 => {
|
||
// map with stable ids based on nextPage
|
||
const base = (nextPage - 1) * that.data.page_size;
|
||
const newList = res.list.map((item, index) => {
|
||
item.id = 'm' + (base + index);
|
||
item.content = JSON.parse(item.content);
|
||
return item;
|
||
});
|
||
|
||
// prepend older messages
|
||
const combined = newList.concat(that.data.messages);
|
||
|
||
that.setData({
|
||
messages: combined,
|
||
page: nextPage,
|
||
total: res.total,
|
||
}, () => {
|
||
// after render, keep the previous top message in view
|
||
if (prevTopId) {
|
||
// scroll-into-view to the previous top id so viewport doesn't jump
|
||
that.setData({ scrollToId: prevTopId });
|
||
}
|
||
that.setData({ loadingMore: false });
|
||
});
|
||
}).catch(() => {
|
||
that.setData({ loadingMore: false });
|
||
});
|
||
},
|
||
// 静默登录方法,只需要appid和js_code
|
||
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()
|
||
// start polling once user info exists
|
||
that.startPolling();
|
||
});
|
||
}).catch(err => {
|
||
console.error('静默登录失败:', err);
|
||
// 如果静默登录失败,可以选择显示授权弹窗或其他处理
|
||
that.setData({
|
||
showGetUser: true
|
||
});
|
||
});
|
||
},
|
||
fail: function(err) {
|
||
console.error('wx.login失败:', err);
|
||
}
|
||
});
|
||
},
|
||
|
||
// Start polling messages every 1 second. Ensures only one interval exists.
|
||
startPolling() {
|
||
if (this.poller) return; // already polling
|
||
// immediate fetch then periodic
|
||
this.getMessages();
|
||
this.poller = setInterval(() => {
|
||
this.getMessages();
|
||
}, 1000);
|
||
},
|
||
|
||
// Stop polling and clear interval
|
||
stopPolling() {
|
||
if (this.poller) {
|
||
clearInterval(this.poller);
|
||
this.poller = null;
|
||
}
|
||
},
|
||
|
||
// Scroll handlers: stop polling when user scrolls up, resume when reach bottom
|
||
onScroll(e) {
|
||
// e.detail.scrollTop increases when scrolling down. We want to detect upward scroll.
|
||
const scrollTop = e.detail.scrollTop || 0;
|
||
const last = this._lastScrollTop || 0;
|
||
// If user scrolls up (new scrollTop < last), pause polling
|
||
if (scrollTop < last) {
|
||
// user scrolled up
|
||
if (this.data.isAtBottom) {
|
||
// only act if we were previously at bottom
|
||
this.setData({ isAtBottom: false });
|
||
this.stopPolling();
|
||
}
|
||
}
|
||
// detect reaching near top to load more
|
||
if (scrollTop <= 2) {
|
||
// if there are more messages to load and not already loading
|
||
if (!this.data.loadingMore && this.data.messages.length < this.data.total) {
|
||
this.loadMoreAtTop();
|
||
}
|
||
}
|
||
// update lastScrollTop for next event
|
||
this._lastScrollTop = scrollTop;
|
||
},
|
||
|
||
onScrollToLower() {
|
||
// user scrolled to bottom (or very near). resume polling if needed
|
||
if (!this.data.isAtBottom) {
|
||
this.setData({ isAtBottom: true });
|
||
this.startPolling();
|
||
// also ensure we scroll to latest message next render
|
||
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 });
|
||
}
|
||
}
|
||
},
|
||
|
||
|
||
|
||
onReady() {
|
||
// 初始化欢迎消息,带时间分割线
|
||
const now = new Date();
|
||
const timeStr = this.formatTime(now);
|
||
this.setData({
|
||
messages: [],
|
||
scrollToId: 'm1'
|
||
});
|
||
},
|
||
|
||
onInput(e) {
|
||
this.setData({
|
||
inputText: e.detail.value
|
||
});
|
||
},
|
||
|
||
sendText() {
|
||
const text = this.data.inputText && this.data.inputText.trim();
|
||
if (!text) return;
|
||
const now = new Date();
|
||
const id = 'u' + Date.now();
|
||
// const timeStr = this.formatTime(now);
|
||
// // 判断是否需要显示时间分割线
|
||
// let showTime = false;
|
||
// const lastMsg = this.data.messages.length ? this.data.messages[this.data.messages.length - 1] : null;
|
||
// if (!lastMsg || now - (lastMsg._ts || now) > 5 * 60 * 1000) showTime = true;
|
||
const msg = {
|
||
id,
|
||
content: {
|
||
messages: 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);
|
||
this.setData({
|
||
messages: newMessages,
|
||
inputText: ''
|
||
});
|
||
const accountInfo = wx.getAccountInfoSync();
|
||
const userInfo = wx.getStorageSync('user_info')
|
||
request('app/send_message', 'POST', {
|
||
"app_id": accountInfo.miniProgram.appId,
|
||
"content": JSON.stringify({
|
||
messages: text
|
||
}),
|
||
"from_user_id": userInfo.openid,
|
||
"from_user_name": userInfo.user_name,
|
||
"msg_type": 1
|
||
})
|
||
// 等待渲染,确保 scroll-into-view 生效
|
||
setTimeout(() => {
|
||
this.setData({
|
||
scrollToId: id
|
||
});
|
||
}, 50);
|
||
|
||
// 模拟客服回复(延迟)
|
||
// setTimeout(() => {
|
||
// const replyNow = new Date();
|
||
// const replyTimeStr = this.formatTime(replyNow);
|
||
// const reply = {
|
||
// id: 's' + Date.now(),
|
||
// from: 'service',
|
||
// type: 'text',
|
||
// content: '收到,客服正在处理中...',
|
||
// showTime: false,
|
||
// timeStr: replyTimeStr,
|
||
// _ts: replyNow
|
||
// };
|
||
// this.setData({
|
||
// messages: this.data.messages.concat(reply),
|
||
// scrollToId: reply.id
|
||
// });
|
||
// }, 800);
|
||
},
|
||
|
||
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 now = new Date();
|
||
const id = 'u' + Date.now();
|
||
// const timeStr = that.formatTime(now);
|
||
// let showTime = false;
|
||
// const lastMsg = that.data.messages.length ? that.data.messages[that.data.messages.length - 1] : null;
|
||
// if (!lastMsg || now - (lastMsg._ts || now) > 5 * 60 * 1000) showTime = true;
|
||
const msg = {
|
||
id,
|
||
msg_type: '2',
|
||
receiver_id: '',
|
||
content: {
|
||
messages: 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);
|
||
|
||
wx.uploadFile({
|
||
filePath: tempFilePaths[0], // 图片临时文件路径
|
||
name: 'file', // 服务器接收文件的字段名,需与后端对应
|
||
url: 'https://mini-chat.1024tool.vip/admin/upload/image', // 服务器接收图片的接口地址
|
||
success: (res) => {
|
||
const data = JSON.parse(res.data);
|
||
console.log('上传成功', data);
|
||
const accountInfo = wx.getAccountInfoSync();
|
||
|
||
request('app/send_message', 'POST', {
|
||
"app_id": accountInfo.miniProgram.appId,
|
||
"content": JSON.stringify({
|
||
messages: 'https://mini-chat.1024tool.vip/'+ data.preview_image_url
|
||
}),
|
||
"from_user_id": userInfo.openid,
|
||
"from_user_name": userInfo.user_name,
|
||
"msg_type": 2
|
||
})
|
||
},
|
||
fail: (err) => {
|
||
console.error('上传失败', err);
|
||
}
|
||
});
|
||
|
||
// 模拟客服返回图片确认
|
||
// setTimeout(() => {
|
||
// const replyNow = new Date();
|
||
// const replyTimeStr = that.formatTime(replyNow);
|
||
// const reply = {
|
||
// id: 's' + Date.now(),
|
||
// from: 'service',
|
||
// type: 'text',
|
||
// content: '已收到图片,感谢!',
|
||
// showTime: false,
|
||
// timeStr: replyTimeStr,
|
||
// _ts: replyNow
|
||
// };
|
||
// that.setData({
|
||
// messages: that.data.messages.concat(reply)
|
||
// });
|
||
// setTimeout(() => {
|
||
// that.setData({
|
||
// scrollToId: reply.id
|
||
// });
|
||
// }, 50);
|
||
// }, 1200);
|
||
}
|
||
}
|
||
});
|
||
},
|
||
// 时间格式化
|
||
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() {
|
||
// resume polling when page becomes visible
|
||
if (wx.getStorageSync('user_info')) {
|
||
this.startPolling();
|
||
}
|
||
},
|
||
onHide() {
|
||
// stop polling when leaving page
|
||
this.stopPolling();
|
||
},
|
||
onUnload() {
|
||
// cleanup
|
||
this.stopPolling();
|
||
},
|
||
onPullDownRefresh() { },
|
||
onReachBottom() { },
|
||
onShareAppMessage() { }
|
||
}); |