378 lines
8.1 KiB
Vue
378 lines
8.1 KiB
Vue
<template>
|
||
<view class="system-message-page">
|
||
<!-- 页面加载状态 -->
|
||
<Loading type="page" :loading="pageLoading" />
|
||
|
||
<!-- 顶部背景图 -->
|
||
<view class="top-bg">
|
||
<image src="/static/title_bg.png" mode="aspectFill" class="bg-img" />
|
||
</view>
|
||
|
||
<!-- 自定义导航栏 -->
|
||
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||
<view class="navbar-content">
|
||
<view class="navbar-back" @click="handleBack">
|
||
<text class="back-icon">‹</text>
|
||
</view>
|
||
<text class="navbar-title">系统消息</text>
|
||
<view class="navbar-placeholder"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 筛选标签 -->
|
||
<view class="filter-section" :style="{ top: (statusBarHeight + 44) + 'px' }">
|
||
<view
|
||
class="filter-tag"
|
||
:class="{ active: currentFilter === 'all' }"
|
||
@click="handleFilterChange('all')"
|
||
>
|
||
全部
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 消息列表 -->
|
||
<scroll-view
|
||
class="message-scroll"
|
||
scroll-y
|
||
:style="{
|
||
top: (statusBarHeight + 44 + 60) + 'px',
|
||
height: scrollHeight + 'px'
|
||
}"
|
||
refresher-enabled
|
||
:refresher-triggered="isRefreshing"
|
||
@refresherrefresh="handleRefresh"
|
||
@scrolltolower="handleLoadMore"
|
||
>
|
||
<view class="message-list" v-if="messageList.length > 0">
|
||
<view
|
||
class="message-item"
|
||
v-for="item in messageList"
|
||
:key="item.id"
|
||
@click="handleMessageClick(item)"
|
||
>
|
||
<view class="message-title">{{ item.title }}</view>
|
||
<view class="message-content">{{ item.content }}</view>
|
||
<view class="message-time">{{ formatTime(item.createTime) }}</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 空状态 -->
|
||
<view class="empty-wrapper" v-else-if="!pageLoading">
|
||
<Empty text="暂无系统消息" :showButton="false" />
|
||
</view>
|
||
|
||
<!-- 加载更多 -->
|
||
<Loading type="more" :loading="listLoading" :noMore="noMoreData" />
|
||
</scroll-view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { ref, onMounted } from 'vue'
|
||
import { useUserStore } from '@/store/user.js'
|
||
import { getSystemMessages } from '@/api/message.js'
|
||
import { formatTimestamp } from '@/utils/format.js'
|
||
import Loading from '@/components/Loading/index.vue'
|
||
import Empty from '@/components/Empty/index.vue'
|
||
|
||
export default {
|
||
name: 'SystemMessagePage',
|
||
components: {
|
||
Loading,
|
||
Empty
|
||
},
|
||
setup() {
|
||
const userStore = useUserStore()
|
||
|
||
// 状态栏高度
|
||
const statusBarHeight = ref(20)
|
||
const scrollHeight = ref(500)
|
||
|
||
// 页面状态
|
||
const pageLoading = ref(true)
|
||
const listLoading = ref(false)
|
||
const noMoreData = ref(false)
|
||
const isRefreshing = ref(false)
|
||
|
||
// 筛选
|
||
const currentFilter = ref('all')
|
||
|
||
// 分页
|
||
const pageIndex = ref(1)
|
||
const pageSize = 20
|
||
|
||
// 数据
|
||
const messageList = ref([])
|
||
|
||
// 获取系统信息
|
||
const getSystemInfo = () => {
|
||
uni.getSystemInfo({
|
||
success: (res) => {
|
||
statusBarHeight.value = res.statusBarHeight || 20
|
||
// 计算滚动区域高度:窗口高度 - 导航栏高度 - 筛选区域高度
|
||
const navbarHeight = statusBarHeight.value + 44
|
||
const filterHeight = 60
|
||
scrollHeight.value = res.windowHeight - navbarHeight - filterHeight
|
||
}
|
||
})
|
||
}
|
||
|
||
// 返回
|
||
const handleBack = () => {
|
||
uni.navigateBack()
|
||
}
|
||
|
||
// 加载消息列表
|
||
const loadMessages = async (isLoadMore = false) => {
|
||
if (listLoading.value) return
|
||
if (isLoadMore && noMoreData.value) return
|
||
|
||
listLoading.value = true
|
||
try {
|
||
if (!isLoadMore) {
|
||
pageIndex.value = 1
|
||
messageList.value = []
|
||
noMoreData.value = false
|
||
}
|
||
|
||
const res = await getSystemMessages({
|
||
pageIndex: pageIndex.value,
|
||
pageSize: pageSize
|
||
})
|
||
|
||
if (res && (res.code === 0 || res.success) && res.data) {
|
||
const items = res.data.items || res.data.list || []
|
||
const total = res.data.total || 0
|
||
|
||
if (isLoadMore) {
|
||
messageList.value = [...messageList.value, ...items]
|
||
} else {
|
||
messageList.value = items
|
||
}
|
||
|
||
noMoreData.value = messageList.value.length >= total || items.length < pageSize
|
||
pageIndex.value++
|
||
}
|
||
} catch (error) {
|
||
console.error('加载系统消息失败:', error)
|
||
} finally {
|
||
listLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 初始化页面
|
||
const initPage = async () => {
|
||
pageLoading.value = true
|
||
try {
|
||
getSystemInfo()
|
||
userStore.restoreFromStorage()
|
||
await loadMessages()
|
||
} catch (error) {
|
||
console.error('初始化页面失败:', error)
|
||
} finally {
|
||
pageLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 筛选切换
|
||
const handleFilterChange = (filter) => {
|
||
if (currentFilter.value === filter) return
|
||
currentFilter.value = filter
|
||
loadMessages()
|
||
}
|
||
|
||
// 下拉刷新
|
||
const handleRefresh = async () => {
|
||
isRefreshing.value = true
|
||
try {
|
||
await loadMessages()
|
||
} finally {
|
||
isRefreshing.value = false
|
||
}
|
||
}
|
||
|
||
// 加载更多
|
||
const handleLoadMore = () => {
|
||
if (!noMoreData.value && !listLoading.value) {
|
||
loadMessages(true)
|
||
}
|
||
}
|
||
|
||
// 点击消息
|
||
const handleMessageClick = (item) => {
|
||
// 如果有跳转链接
|
||
if (item.linkUrl) {
|
||
uni.navigateTo({ url: item.linkUrl })
|
||
}
|
||
}
|
||
|
||
// 格式化时间
|
||
const formatTime = (timestamp) => {
|
||
return formatTimestamp(timestamp)
|
||
}
|
||
|
||
onMounted(() => {
|
||
initPage()
|
||
})
|
||
|
||
return {
|
||
statusBarHeight,
|
||
scrollHeight,
|
||
pageLoading,
|
||
listLoading,
|
||
noMoreData,
|
||
isRefreshing,
|
||
currentFilter,
|
||
messageList,
|
||
handleBack,
|
||
handleFilterChange,
|
||
handleRefresh,
|
||
handleLoadMore,
|
||
handleMessageClick,
|
||
formatTime
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.system-message-page {
|
||
height: 100vh;
|
||
background-color: #f5f6fa;
|
||
}
|
||
|
||
// 顶部背景图
|
||
.top-bg {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 400rpx;
|
||
z-index: 0;
|
||
|
||
.bg-img {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
|
||
// 自定义导航栏
|
||
.custom-navbar {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 100;
|
||
|
||
.navbar-content {
|
||
position: relative;
|
||
height: 44px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 24rpx;
|
||
|
||
.navbar-back {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.back-icon {
|
||
font-size: 56rpx;
|
||
color: #333;
|
||
font-weight: 300;
|
||
}
|
||
}
|
||
|
||
.navbar-title {
|
||
font-size: 34rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
|
||
.navbar-placeholder {
|
||
width: 80rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 筛选标签
|
||
.filter-section {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 10;
|
||
padding: 16rpx 24rpx;
|
||
|
||
.filter-tag {
|
||
display: inline-block;
|
||
padding: 12rpx 32rpx;
|
||
font-size: 28rpx;
|
||
color: #ff6b6b;
|
||
background: #fff;
|
||
border: 2rpx solid #ff6b6b;
|
||
border-radius: 32rpx;
|
||
|
||
&.active {
|
||
color: #ff6b6b;
|
||
background: #fff;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 消息滚动区域
|
||
.message-scroll {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
background-color: #f5f6fa;
|
||
}
|
||
|
||
// 消息列表
|
||
.message-list {
|
||
padding: 24rpx;
|
||
min-height: 100%;
|
||
|
||
.message-item {
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
padding: 32rpx;
|
||
margin-bottom: 24rpx;
|
||
|
||
&:active {
|
||
background: #f8f8f8;
|
||
}
|
||
|
||
.message-title {
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 16rpx;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.message-content {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
line-height: 1.8;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.message-time {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 空状态
|
||
.empty-wrapper {
|
||
height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
</style>
|