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:
Ubuntu
2026-06-15 21:04:21 +08:00
parent ed9eedc519
commit d1612fe376
9 changed files with 1158 additions and 0 deletions

221
src/views/notice/index.vue Normal file
View 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>