177 lines
4.7 KiB
Vue
177 lines
4.7 KiB
Vue
<template>
|
||
<view class="mailbox-list">
|
||
<!-- 背景图片 -->
|
||
<image class="bg-image" src="/static/square/squearbj.png" mode="aspectFill"></image>
|
||
<!-- <Header title="收件箱" :showBack="true" /> -->
|
||
<view class="toolbar">
|
||
<view class="nav-back" @tap="goBack">
|
||
<text class="nav-back-icon">←</text>
|
||
</view>
|
||
<button class="btn-mark-all" @click="onMarkAllRead">[+全部已读]</button>
|
||
<button class="btn-delete-all" @click="onClearAll">[+全部删除]</button>
|
||
</view>
|
||
|
||
<scroll-view scroll-y="true" class="list-scroll" @scrolltolower="onScrollLower">
|
||
<MailboxGroup v-for="grp in GROUPS" :key="grp.type" :groupKey="grp.type" :label="grp.label"
|
||
:collapsed="isCollapsed(grp.type)" :items="itemsByType[grp.type]" :unreadCount="unreadByType[grp.type] || 0"
|
||
@toggle="toggleCollapse(grp.type)" @select="onSelectItem" @long-press="onLongPress" />
|
||
<!-- <view v-if="!hasAny && !loading" class="empty">暂无通知</view> -->
|
||
<view v-if="loading" class="loading">加载中...</view>
|
||
<view v-if="hasAny && !hasMore" class="no-more">没有更多了</view>
|
||
</scroll-view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { onLoad, onShow, onHide, onPullDownRefresh } from '@dcloudio/uni-app'
|
||
import { useStore } from 'vuex'
|
||
// import Header from '../components/Header.vue'
|
||
import MailboxGroup from './components/MailboxGroup.vue'
|
||
import { useMailboxCenter } from './composables/useMailboxCenter.js'
|
||
|
||
const {
|
||
GROUPS, itemsByType, unreadByType,
|
||
loading, hasAny, hasMore,
|
||
loadAll, onScrollLower,
|
||
onMarkAllRead, onClearAll,
|
||
onSelectItem, onLongPress,
|
||
isCollapsed, toggleCollapse,
|
||
onMarkRead,
|
||
} = useMailboxCenter()
|
||
|
||
const store = useStore()
|
||
|
||
const goBack = () => {
|
||
// 获取页面栈
|
||
const pages = getCurrentPages();
|
||
if (pages.length > 1) {
|
||
// 有上一页,执行返回
|
||
uni.navigateBack();
|
||
} else {
|
||
// 没有上一页,跳转到square页面
|
||
uni.reLaunch({
|
||
url: '/pages/square/square'
|
||
});
|
||
}
|
||
};
|
||
|
||
// P1-5 fix:App.vue 推送 click 带 ?focus=mailbox&nid=N&type=T 跳进来,
|
||
// 这里读 query → 标记已读 → 跳到详情。让"点推送"直达具体消息,不再只是"进收件箱"。
|
||
// 用 composable 已有的 onMarkRead(nid, type),不走 store 的同名 action(不存在)。
|
||
let focusHandled = false
|
||
onLoad((options) => {
|
||
if (!options || focusHandled) return
|
||
const nid = Number(options.nid)
|
||
const type = options.type || ''
|
||
if (nid && type) {
|
||
focusHandled = true
|
||
// fire-and-forget:失败仅 warn,不影响用户进站
|
||
onMarkRead(nid, type).catch((e) => {
|
||
console.warn('[mailbox/index] markAsRead from push failed:', e)
|
||
})
|
||
uni.navigateTo({ url: `/pages/mailbox/detail?nid=${nid}&type=${encodeURIComponent(type)}` })
|
||
}
|
||
})
|
||
|
||
// P1-2 fix:用户停留在收件箱页时,推送来要 PREPEND_ITEM(否则只剩角标更新、列表无新条目)。
|
||
// onShow 置 SET_IS_IN_PAGE=true,onHide=false。App.vue 走 mailbox/applyPushPayload 时,
|
||
// mailbox store 的 applyPushPayload 会读 rootState.mailbox.isInMailboxPage 决定是否 PREPEND_ITEM。
|
||
onShow(() => {
|
||
store.commit('mailbox/SET_IS_IN_PAGE', true)
|
||
loadAll()
|
||
})
|
||
onHide(() => {
|
||
store.commit('mailbox/SET_IS_IN_PAGE', false)
|
||
})
|
||
|
||
// 下拉刷新:补 trigger loadAll + 收尾 stopPullDownRefresh
|
||
// (pages.json 配了 enablePullDownRefresh: true 才有效)
|
||
onPullDownRefresh(async () => {
|
||
try {
|
||
await loadAll()
|
||
} finally {
|
||
uni.stopPullDownRefresh()
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.mailbox-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100vh;
|
||
background: #f8f8f8;
|
||
|
||
/* 背景图片 */
|
||
.bg-image {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 120%;
|
||
z-index: 0;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.toolbar {
|
||
display: flex;
|
||
gap: 16rpx;
|
||
padding: 96rpx 24rpx 16rpx;
|
||
// background: #fff;
|
||
// border-bottom: 1rpx solid #f0f0f0;
|
||
position: relative;
|
||
|
||
.nav-back {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
/* background: rgba(255,255,255,0.5);
|
||
border-radius: 50%; */
|
||
}
|
||
|
||
.nav-back-icon {
|
||
font-size: 48rpx;
|
||
font-weight: bold;
|
||
color: #fff;
|
||
}
|
||
|
||
button {
|
||
flex: 1;
|
||
font-size: 26rpx;
|
||
padding: 12rpx 0;
|
||
border-radius: 8rpx;
|
||
|
||
&::after {
|
||
border: 0;
|
||
}
|
||
}
|
||
|
||
.btn-mark-all {
|
||
background: #e8f4ff;
|
||
color: #5C40FF;
|
||
}
|
||
|
||
.btn-delete-all {
|
||
background: #fff1f0;
|
||
color: #f5222d;
|
||
}
|
||
}
|
||
|
||
.list-scroll {
|
||
flex: 1;
|
||
overflow: hidden;
|
||
padding: 16rpx 24rpx;
|
||
}
|
||
|
||
.empty,
|
||
.loading,
|
||
.no-more {
|
||
text-align: center;
|
||
color: #999;
|
||
font-size: 26rpx;
|
||
padding: 48rpx 0;
|
||
}
|
||
}
|
||
</style> |