wewew
This commit is contained in:
parent
7e88dbb16c
commit
7477992bc7
@ -17,8 +17,13 @@ Page({
|
||||
userInfo: {},
|
||||
appid: '',
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
page_size: 50,
|
||||
openid: '',
|
||||
total: 0,
|
||||
// 是否滚动在底部
|
||||
isAtBottom: true,
|
||||
// 正在加载更多(顶部分页)
|
||||
loadingMore: false,
|
||||
},
|
||||
|
||||
/**
|
||||
@ -39,6 +44,8 @@ Page({
|
||||
userInfo: wx.getStorageSync('user_info'),
|
||||
});
|
||||
this.getMessages()
|
||||
// start polling when page loads and user is present
|
||||
this.startPolling();
|
||||
} else {
|
||||
this.setData({
|
||||
showGetUser: true,
|
||||
@ -64,15 +71,73 @@ Page({
|
||||
page_size: this.data.page_size,
|
||||
}).then(res => {
|
||||
console.log('res', res);
|
||||
const list = res.list.map(item => {
|
||||
// generate stable ids across pages so we can prepend without collisions
|
||||
const base = (this.data.page - 1) * this.data.page_size;
|
||||
const list = res.list.map((item, index) => {
|
||||
item.id = 'm' + (base + index);
|
||||
item.content = JSON.parse(item.content);
|
||||
return item;
|
||||
});
|
||||
this.setData({
|
||||
messages: list,
|
||||
total: res.total,
|
||||
// only auto-scroll if user is at bottom
|
||||
scrollToId: this.data.isAtBottom ? (list[list.length - 1] ? list[list.length - 1].id : '') : this.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 });
|
||||
});
|
||||
},
|
||||
requestUserProfile(e) {
|
||||
console.log('user', e.detail);
|
||||
const user = e.detail;
|
||||
@ -102,6 +167,8 @@ Page({
|
||||
"user_name": resp.user_name
|
||||
}).then(resp => {
|
||||
that.getMessages()
|
||||
// start polling once user info exists
|
||||
that.startPolling();
|
||||
|
||||
});
|
||||
});
|
||||
@ -110,6 +177,62 @@ Page({
|
||||
|
||||
},
|
||||
|
||||
// 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 });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
dismissGetUser() {
|
||||
this.setData({
|
||||
showGetUser: false
|
||||
@ -121,14 +244,7 @@ Page({
|
||||
const now = new Date();
|
||||
const timeStr = this.formatTime(now);
|
||||
this.setData({
|
||||
messages: [{
|
||||
id: 'm1',
|
||||
from: 'service',
|
||||
type: 'text',
|
||||
content: '您好!请问有什么可以帮您?',
|
||||
showTime: true,
|
||||
timeStr
|
||||
}],
|
||||
messages: [],
|
||||
scrollToId: 'm1'
|
||||
});
|
||||
},
|
||||
@ -189,23 +305,23 @@ Page({
|
||||
}, 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);
|
||||
// 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() {
|
||||
@ -291,9 +407,20 @@ Page({
|
||||
});
|
||||
},
|
||||
|
||||
onShow() {},
|
||||
onHide() {},
|
||||
onUnload() {},
|
||||
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() {}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<text class="header-title">租号客服</text>
|
||||
</view> -->
|
||||
|
||||
<scroll-view class="messages" scroll-y="true" scroll-into-view="{{scrollToId}}">
|
||||
<scroll-view class="messages" scroll-y="true" scroll-into-view="{{scrollToId}}" bindscroll="onScroll" bindscrolltolower="onScrollToLower" lower-threshold="20">
|
||||
<block wx:for="{{messages}}" wx:key="id">
|
||||
<!-- 时间分割线 -->
|
||||
<block wx:if="{{item.showTime}}">
|
||||
@ -17,16 +17,18 @@
|
||||
<image class="avatar" src="{{item.sender_id == userInfo.openid ? userAvatar : serviceAvatar}}" />
|
||||
|
||||
</view>
|
||||
<view class="bubble">
|
||||
<block wx:if="{{item.msg_type == 1}}">
|
||||
<text class="msg-text">{{item.content.messages}}</text>
|
||||
</block>
|
||||
<block wx:elif="{{item.msg_type == 2}}">
|
||||
<image src="{{item.content.messages}}" bindtap="previewImage" data-src="{{item.content.messages}}" class="msg-image" mode="aspectFill" />
|
||||
</block>
|
||||
</view>
|
||||
<view class="bubble-wrap">
|
||||
<view class="bubble">
|
||||
<block wx:if="{{item.msg_type == 1}}">
|
||||
<text class="msg-text">{{item.content.messages}}</text>
|
||||
</block>
|
||||
<block wx:elif="{{item.msg_type == 2}}">
|
||||
<image src="{{item.content.messages}}" bindtap="previewImage" data-src="{{item.content.messages}}" class="msg-image" mode="aspectFill" />
|
||||
</block>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="send-time">{{item.send_time}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
|
||||
@ -112,6 +112,23 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* bubble-wrap stacks bubble above the timestamp */
|
||||
.bubble-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start; /* will be overridden for .user */
|
||||
}
|
||||
|
||||
/* For user messages, bubble-wrap should align to the right */
|
||||
.message.user .bubble-wrap {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
/* For service messages, bubble-wrap aligns to the left */
|
||||
.message.service .bubble-wrap {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
@ -149,6 +166,25 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 发送时间样式(气泡下方) */
|
||||
.send-time {
|
||||
font-size: 22rpx;
|
||||
color: #9aa0a6;
|
||||
margin-top: 6rpx;
|
||||
/* keep the timestamp small and unobtrusive */
|
||||
}
|
||||
|
||||
/* 不同发送方时间对齐 */
|
||||
.message.user .send-time {
|
||||
text-align: right;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.message.service .send-time {
|
||||
text-align: left;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
|
||||
/* 输入栏 */
|
||||
.input-area {
|
||||
background: #fff;
|
||||
@ -263,4 +299,19 @@
|
||||
padding: 12rpx 20rpx;
|
||||
border-radius: 8rpx;
|
||||
border: 1px solid #eee
|
||||
}
|
||||
|
||||
/* Keep bubble-wrap in the same order/place as the original bubble
|
||||
so we don't change the horizontal layout. Only adjust order and
|
||||
tiny margins - do not change existing bubble/avatar styles. */
|
||||
.message.user .bubble-wrap {
|
||||
order: 1; /* same as previous .bubble order for user */
|
||||
margin-right: 8rpx; /* match bubble spacing */
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.message.service .bubble-wrap {
|
||||
order: 2; /* same as previous .bubble order for service */
|
||||
margin-left: 8rpx; /* match bubble spacing */
|
||||
margin-right: 0;
|
||||
}
|
||||
@ -23,21 +23,21 @@
|
||||
"miniprogram": {
|
||||
"list": [
|
||||
{
|
||||
"name": "pages/contact/index",
|
||||
"pathName": "pages/contact/index",
|
||||
"name": "pages/index/detail",
|
||||
"pathName": "pages/index/detail",
|
||||
"query": "url=1",
|
||||
"scene": null,
|
||||
"launchMode": "default"
|
||||
},
|
||||
{
|
||||
"name": "pages/index/detail",
|
||||
"pathName": "pages/index/detail",
|
||||
"query": "url=1&app_id=wx26ad074017e1e63f",
|
||||
"name": "pages/contact/index",
|
||||
"pathName": "pages/contact/index",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"libVersion": "3.9.2"
|
||||
"libVersion": "3.10.3"
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user