230 lines
5.3 KiB
Vue
230 lines
5.3 KiB
Vue
<template>
|
||
<view class="page">
|
||
<view class="status_bar"></view>
|
||
<!-- 固定导航栏 -->
|
||
<uni-nav-bar
|
||
left-icon="left"
|
||
title="通知公告"
|
||
background-color="#F9F9F9"
|
||
@clickLeft="narBack"
|
||
/>
|
||
|
||
<!-- 滚动区域(能正常滚动的核心) -->
|
||
<scroll-view
|
||
scroll-y
|
||
class="scroll-box"
|
||
:refresher-enabled="true"
|
||
:refresher-triggered="refreshing"
|
||
@refresherrefresh="onRefresh"
|
||
@scrolltolower="loadMore"
|
||
>
|
||
<view class="list-wrap">
|
||
<!-- 下拉刷新 -->
|
||
<view class="refresh" v-if="refreshing">
|
||
<uni-icons type="spinner-cycle" class="spin"/> 刷新中...
|
||
</view>
|
||
|
||
<!-- 列表 -->
|
||
<view
|
||
v-for="notice in noticeList"
|
||
:key="notice.noticeId"
|
||
class="item">
|
||
<view class="title-box">
|
||
<view class="title">{{ notice.noticeTitle }}</view>
|
||
<view class="dot" v-if="notice.readStatus === '0'"></view>
|
||
</view>
|
||
<view class="info">{{ notice.author }} · {{ notice.publishTime }}</view>
|
||
<view class="content">{{ notice.noticeContent }}</view>
|
||
<view class="detail" @click="goToDetail(notice)">
|
||
<text style="color:#2F77FD">详情</text>
|
||
<uni-icons type="right" size="13" color="#007AFF"/>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 加载中 / 无更多 / 空布局 -->
|
||
<view class="load-more" v-if="loadingMore">加载中...</view>
|
||
<view class="no-more" v-if="noMoreData && noticeList.length">没有更多通知了</view>
|
||
<view class="empty" v-if="noticeList.length === 0 && !loading">
|
||
暂无通知
|
||
<!-- <button class="refresh-btn" @click="loadNotices">刷新试试</button> -->
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref } from 'vue'
|
||
import { onLoad ,onShow,onUnload} from '@dcloudio/uni-app'
|
||
import { getNoticeList } from '../api/api.js'
|
||
|
||
const noticeList = ref([])
|
||
const refreshing = ref(false)
|
||
const loadingMore = ref(false)
|
||
const noMoreData = ref(false)
|
||
const loading = ref(false)
|
||
const pageNum = ref(1)
|
||
const pageSize = 10
|
||
const isFirstShow = ref(true) // 详情返回列表刷新状态
|
||
|
||
const goToDetail = (notice) => {
|
||
uni.navigateTo({
|
||
url: `/pageSubPack/notice-list/noticeListDetails?id=${notice.noticeId}`
|
||
})
|
||
}
|
||
|
||
const loadNotices = async (isRefresh = false) => {
|
||
if (loading.value) return
|
||
loading.value = true
|
||
if (isRefresh) {
|
||
pageNum.value = 1
|
||
noMoreData.value = false
|
||
}
|
||
try {
|
||
const res = await getNoticeList({ pageNum: pageNum.value, pageSize })
|
||
if (res.code === 200) {
|
||
const list = res.data.rows || []
|
||
noticeList.value = isRefresh ? list : [...noticeList.value, ...list]
|
||
if (list.length < pageSize) noMoreData.value = true
|
||
}
|
||
} catch (e) {}
|
||
finally {
|
||
loading.value = false
|
||
refreshing.value = false
|
||
loadingMore.value = false
|
||
}
|
||
}
|
||
// 更新单条已读状态
|
||
const updateReadStatus = ({ noticeId, readStatus }) => {
|
||
const item = noticeList.value.find(n => String(n.noticeId) === noticeId)
|
||
if (item) {
|
||
item.readStatus = readStatus
|
||
}
|
||
}
|
||
|
||
onShow(() =>{
|
||
if(isFirstShow.value) return
|
||
loadNotices(true)
|
||
})
|
||
|
||
const onRefresh = () => {
|
||
refreshing.value = true
|
||
loadNotices(true)
|
||
}
|
||
|
||
const loadMore = () => {
|
||
if (noMoreData.value || loadingMore.value) return
|
||
loadingMore.value = true
|
||
pageNum.value++
|
||
loadNotices()
|
||
}
|
||
|
||
const narBack = () => {
|
||
const page = uni.getStorageSync('sourcePage')
|
||
if (page === 'index') uni.switchTab({ url: '/pages/index/index' })
|
||
if (page === 'serviceIndex') uni.switchTab({ url: '/pages/serviceIndex/serviceIndex' })
|
||
uni.removeStorageSync('sourcePage')
|
||
}
|
||
|
||
onLoad(() => {
|
||
isFirstShow.value = false
|
||
uni.$on('noticeRead',updateReadStatus)
|
||
loadNotices(true)
|
||
})
|
||
onUnload(()=>{
|
||
uni.$off('noticeRead',updateReadStatus)
|
||
})
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
page {
|
||
background: #f9f9f9;
|
||
}
|
||
.page {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.status_bar {
|
||
height: 46px;
|
||
width: 100%;
|
||
}
|
||
.scroll-box {
|
||
flex: 1;
|
||
height: 0; /* 让滚动区域生效 */
|
||
}
|
||
.list-wrap {
|
||
padding: 40rpx;
|
||
}
|
||
.item {
|
||
background: #fff;
|
||
border-radius: 12rpx;
|
||
padding: 30rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
.title-box {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
.title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
width: 500rpx;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.dot {
|
||
width: 12rpx;
|
||
height: 12rpx;
|
||
background: red;
|
||
border-radius: 50%;
|
||
}
|
||
.info {
|
||
color: #999;
|
||
font-size: 24rpx;
|
||
margin: 10rpx 0;
|
||
}
|
||
.content {
|
||
color: #666;
|
||
font-size: 28rpx;
|
||
line-height: 1.5;
|
||
margin: 20rpx 0;
|
||
background-color: #f9f9f9;
|
||
padding: 24rpx;
|
||
}
|
||
.detail {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
.refresh, .load-more, .no-more {
|
||
text-align: center;
|
||
padding: 20rpx;
|
||
color: #999;
|
||
}
|
||
.empty {
|
||
text-align: center;
|
||
padding: 100rpx 0;
|
||
color: #999;
|
||
}
|
||
.refresh-btn {
|
||
background: #007AFF;
|
||
color: #fff;
|
||
border-radius: 50rpx;
|
||
padding: 10rpx 30rpx;
|
||
margin-top: 20rpx;
|
||
}
|
||
.spin {
|
||
animation: rotate 1s linear infinite;
|
||
}
|
||
@keyframes rotate {
|
||
0% { transform: rotate(0deg); }
|
||
100% { transform: rotate(360deg); }
|
||
}
|
||
</style> |