Files
yuto-water-h5/src/views/notice/index.vue
Ubuntu d1612fe376 feat: Batch 1 - basic pages (scanCode/privacyPolicy/resetPwd/notice/menuEdit/addGroup)
Agent Loop: 2 agents, both passed on iteration 1
6 new pages + 6 routes added
2026-06-15 21:04:21 +08:00

222 lines
4.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
/**
* 消息通知页面
*
* 使用 Vant PullRefresh + List 实现下拉刷新和无限滚动,
* Tabs 切换"未读消息"和"全部消息"。
*/
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { showToast } from 'vant'
const router = useRouter()
/** 当前激活的 Tab */
const activeName = ref('未读消息')
/** 列表数据 */
const list = ref<any[]>([])
/** 是否加载完成 */
const finished = ref(false)
/** 是否正在加载 */
const isLoading = ref(false)
/** 分页参数 */
const pageParams = reactive({
pageNum: 1,
pageSize: 10,
})
/**
* 生成模拟消息数据
*/
function generateMockData(pageNum: number, pageSize: number) {
const start = (pageNum - 1) * pageSize
const total = 25
const items: any[] = []
const end = Math.min(start + pageSize, total)
for (let i = start; i < end; i++) {
items.push({
id: i + 1,
title: `通知消息标题 ${i + 1}`,
message: `这是第 ${i + 1} 条消息的详细内容,用于展示通知列表的效果。`,
createTime: `2025-06-${String(10 + Math.floor(i / 3)).padStart(2, '0')} 14:30:00`,
})
}
return { items, isLastPage: end >= total }
}
/**
* 获取列表数据
*/
function getList() {
isLoading.value = true
pageParams.pageNum = 1
setTimeout(() => {
const { items, isLastPage } = generateMockData(pageParams.pageNum, pageParams.pageSize)
list.value = items
finished.value = isLastPage
isLoading.value = false
}, 500)
}
/**
* Tab 切换
*/
function onChange(name: string | number) {
activeName.value = String(name)
finished.value = false
getList()
}
/**
* 无限滚动加载更多
*/
function onLoad() {
if (finished.value) return
isLoading.value = true
pageParams.pageNum += 1
setTimeout(() => {
const { items, isLastPage } = generateMockData(pageParams.pageNum, pageParams.pageSize)
list.value = list.value.concat(items)
finished.value = isLastPage
isLoading.value = false
}, 500)
}
/**
* 下拉刷新
*/
function onRefresh() {
finished.value = false
pageParams.pageNum = 1
setTimeout(() => {
const { items, isLastPage } = generateMockData(pageParams.pageNum, pageParams.pageSize)
list.value = items
finished.value = isLastPage
showToast('刷新成功')
}, 800)
}
/**
* 点击消息项
*/
function toDetail(item: any) {
showToast(`查看: ${item.title}`)
}
/** 初始加载 */
getList()
</script>
<template>
<div class="notice-page">
<!-- 顶部导航栏 -->
<van-nav-bar title="消息通知" left-text="返回" left-arrow fixed placeholder @click-left="router.back()" />
<!-- Tab 切换 -->
<van-tabs v-model:active="activeName" @change="onChange" sticky>
<van-tab title="未读消息" name="未读消息" />
<van-tab title="全部消息" name="全部消息" />
</van-tabs>
<!-- 下拉刷新 + 列表 -->
<van-pull-refresh v-model="isLoading" @refresh="onRefresh">
<van-list
v-model:loading="isLoading"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
>
<div
class="notice-item"
v-for="item in list"
:key="item.id"
@click="toDetail(item)"
>
<div class="notice-item-header">
<span class="notice-item-title">{{ item.title }}</span>
</div>
<van-divider />
<div class="notice-item-body">
<span>{{ item.message }}</span>
</div>
<van-divider />
<div class="notice-item-footer">
<span class="notice-item-time-label">通知时间</span>
<span class="notice-item-time">{{ item.createTime }}</span>
</div>
</div>
</van-list>
</van-pull-refresh>
</div>
</template>
<style lang="scss" scoped>
.notice-page {
min-height: 100vh;
background: #f4f7f8;
:deep(.van-nav-bar) {
background: var(--color-primary);
--van-nav-bar-title-text-color: #fff;
--van-nav-bar-text-color: #fff;
--van-nav-bar-icon-color: #fff;
}
}
.notice-item {
padding: 10px 12px;
margin: 12px 8px;
background: #fff;
border-radius: 10px;
cursor: pointer;
&:active {
background: #f5f5f5;
}
&-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 6px;
}
&-title {
flex: 1;
font-size: 17px;
color: #333438;
font-weight: 600;
}
&-body {
padding: 0 4px;
font-size: 14px;
color: #535c66;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
&-footer {
display: flex;
justify-content: space-between;
padding: 0 4px;
}
&-time-label {
font-size: 12px;
color: #999;
}
&-time {
font-size: 12px;
color: #666;
}
}
</style>