feat: 消息与任务列表改为分页加载
此前一次性拉全量(硬编码 limit:100),任务/通知多了会拖慢首屏。 - 分页状态:page / pageSize(20) / hasMore / loadingMore,触底加载下一页 - 下拉刷新回到第 1 页并清空重载 —— 分页后必须重置,否则新旧页会错位 - 任务列表按 id 去重后追加:翻页期间若有新任务插入,分页边界会错位导致 重复项 - hasMore 优先以响应里的 total 为准,缺失时退回「本页是否满员」判断 - 底部新增状态提示(加载中 / 没有更多了 / 上拉加载更多), 让工人知道是「到底了」还是「还在拉」
This commit is contained in:
@ -39,13 +39,18 @@
|
||||
</view>
|
||||
<text class="card-arrow">›</text>
|
||||
</view>
|
||||
|
||||
<!-- ⬇️ 触底加载状态:让工人知道"到底了"还是"还在拉" -->
|
||||
<view v-if="loadingMore" class="load-more">加载中...</view>
|
||||
<view v-else-if="!hasMore" class="load-more">— 没有更多了 —</view>
|
||||
<view v-else class="load-more">上拉加载更多</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { onShow } from "@dcloudio/uni-app";
|
||||
import { onShow, onPullDownRefresh, onReachBottom } from "@dcloudio/uni-app";
|
||||
import { getNotifications, markNotificationRead } from "../../api/notification";
|
||||
|
||||
const TYPE_CONFIG = {
|
||||
@ -58,11 +63,17 @@ const notifications = ref([]);
|
||||
const loading = ref(true);
|
||||
let currentUser = null;
|
||||
|
||||
// 📄 分页状态:此前用默认 limit=20 但翻不动页,第 21 条以后的消息永远看不到
|
||||
const pageSize = 20;
|
||||
let page = 1;
|
||||
const hasMore = ref(true);
|
||||
const loadingMore = ref(false);
|
||||
|
||||
onShow(() => {
|
||||
loadUser();
|
||||
setTimeout(() => {
|
||||
if (!currentUser) loadUser();
|
||||
fetchNotifications();
|
||||
fetchNotifications("initial");
|
||||
}, 200);
|
||||
});
|
||||
|
||||
@ -76,17 +87,69 @@ function loadUser() {
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async function fetchNotifications() {
|
||||
const userId = currentUser?.username || currentUser?.id || "";
|
||||
if (!userId) { loading.value = false; return; }
|
||||
loading.value = true;
|
||||
// 🚀 下拉刷新:界面提示了「请下拉刷新重试」,就必须把功能做实。
|
||||
// 分页后下拉必须重置 page 并清空列表 —— 否则新的第 1 页会和旧的第 2、3 页
|
||||
// 混在一起,出现重复项与排序错乱。
|
||||
onPullDownRefresh(async () => {
|
||||
try {
|
||||
const res = await getNotifications(userId);
|
||||
notifications.value = res.notifications || [];
|
||||
} catch {
|
||||
notifications.value = [];
|
||||
loadUser();
|
||||
await fetchNotifications("refresh");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
uni.stopPullDownRefresh(); // 无论成败都要收起动画,否则会一直挂着
|
||||
}
|
||||
});
|
||||
|
||||
// 🚀 触底加载下一页
|
||||
onReachBottom(() => {
|
||||
if (loading.value || loadingMore.value || !hasMore.value) return;
|
||||
loadingMore.value = true;
|
||||
fetchNotifications("more").finally(() => { loadingMore.value = false; });
|
||||
});
|
||||
|
||||
/**
|
||||
* 拉取通知
|
||||
* @param {'initial'|'refresh'|'more'} mode
|
||||
* initial — 首次进入/切页:显示整页 loading,失败清空
|
||||
* refresh — 下拉刷新:重置到第 1 页并清空重载
|
||||
* more — 触底加载:追加下一页,失败保留已加载内容只提示
|
||||
*/
|
||||
async function fetchNotifications(mode = "initial") {
|
||||
const userId = currentUser?.username || currentUser?.id || "";
|
||||
if (!userId) {
|
||||
if (mode === "initial") loading.value = false;
|
||||
else uni.showToast({ title: "未获取到登录信息,请重新登录", icon: "none", duration: 2500 });
|
||||
return;
|
||||
}
|
||||
// initial / refresh 都要从第 1 页重来:前者是切页回来,后者是下拉刷新。
|
||||
// 若 initial 沿用旧的 page,onShow 只会去拉"第 N 页"并追加,列表永远刷不新。
|
||||
if (mode === "initial" || mode === "refresh") {
|
||||
page = 1;
|
||||
hasMore.value = true;
|
||||
notifications.value = [];
|
||||
}
|
||||
if (mode === "initial") loading.value = true;
|
||||
const target = page;
|
||||
try {
|
||||
const res = await getNotifications(userId, (target - 1) * pageSize, pageSize);
|
||||
const batch = res.notifications || [];
|
||||
// 按 id 去重后追加:翻页期间若来了新消息,分页边界会错位导致重复项
|
||||
const seen = new Set(notifications.value.map((n) => n.id));
|
||||
notifications.value = notifications.value.concat(batch.filter((n) => !seen.has(n.id)));
|
||||
// 后端给了 total 就以它为准;否则退回「本页是否满员」判断
|
||||
hasMore.value = res.total != null
|
||||
? notifications.value.length < res.total
|
||||
: batch.length >= pageSize;
|
||||
if (hasMore.value) page = target + 1;
|
||||
} catch (e) {
|
||||
console.error("[notify] 拉取消息失败:", e);
|
||||
if (mode === "initial") notifications.value = [];
|
||||
else uni.showToast({
|
||||
title: mode === "more" ? "加载更多失败,请重试" : "刷新失败,请稍后重试",
|
||||
icon: "none",
|
||||
duration: 2500,
|
||||
});
|
||||
} finally {
|
||||
if (mode === "initial") loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,4 +228,7 @@ async function handleCardTap(item) {
|
||||
.card-content { font-size: 13px; color: #6b7280; line-height: 1.5; display: block; word-break: break-all; }
|
||||
|
||||
.card-arrow { font-size: 20px; color: #d1d5db; margin-top: 6px; flex-shrink: 0; }
|
||||
|
||||
/* 触底加载状态 */
|
||||
.load-more { text-align: center; font-size: 12px; color: #9ca3af; padding: 16px 0 4px; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user