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
This commit is contained in:
221
src/views/notice/index.vue
Normal file
221
src/views/notice/index.vue
Normal file
@@ -0,0 +1,221 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user