253 lines
6.5 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.

<template>
<PageContainer title="灾毁阻断" @click-back="handleClickBack">
<SearchInput v-model="searchValue" placeholder="请输入地点关键词" @search="handleSearch">
<template #extra>
<!-- 全部按钮激活状态 -->
<van-button type="default" size="small" :class="{ active: activeFilter === 'all' }" @click="activeFilter = 'all'"> 全部 </van-button>
<!-- 筛选按钮带图标 -->
<van-button type="default" size="small" icon="filter-o" @click="showFilter = true"></van-button>
</template>
</SearchInput>
<CurrentSite />
<div class="list-panel">
<CardItem v-for="(item, index) in list" :key="index" :title="item.title" @click="handleClickItem(item)">
<template #headerExtra>
<!-- 使用 Vant Tag 组件显示状态 -->
<van-tag :type="item.status === '未解除' ? 'danger' : 'success'" plain size="medium">
{{ item.status }}
</van-tag>
</template>
<div class="info-block">
<div class="time-box">
<span class="info-label">发生时间</span>
<span class="info-value">{{ item.occurTime }}</span>
</div>
<div class="time-box">
<span class="info-label">预计恢复时间</span>
<span class="info-value">{{ item.estimateRecoverTime }}</span>
</div>
<!-- 使用 Vant Tag 组件显示灾毁类型 -->
<div class="disaster-type-wrapper">
<van-tag type="primary" size="medium" plain>{{ item.disasterType }}</van-tag>
</div>
</div>
<!-- 使用绝对定位的箭头 -->
<van-icon class="jump-icon-absolute" name="arrow" />
</CardItem>
<!-- 加载状态 -->
<div v-if="loading" class="loading-wrapper">
<van-loading size="24px" vertical>加载中...</van-loading>
</div>
<!-- 空状态提示 -->
<EmptyBox v-if="!loading && list.length === 0" :placeholder="emptyText" />
</div>
<!-- 灾毁填报按钮 -->
<van-button type="primary" class="fab-btn" icon="plus" @click="handleAdd"> 冰雪填报 </van-button>
</PageContainer>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { showToast, Tag as VanTag, Loading as VanLoading, Icon as VanIcon, Button as VanButton } from 'vant'
import PageContainer from '@/components/PageContainer.vue'
import SearchInput from '@/components/SearchInput.vue'
import CardItem from '@/components/CardItem.vue'
import EmptyBox from '@/components/EmptyBox.vue'
import CurrentSite from '@/components/CurrentSite.vue'
import mockDataJSON from './mockData.json'
const router = useRouter()
// 搜索关键词
const searchValue = ref('')
// 列表数据
const list = ref([])
// 加载状态
const loading = ref(false)
// 空状态文本
const emptyText = ref('暂无相关灾毁信息')
// 获取灾毁列表数据(后端接口)
const getDisasterList = async (keyword = '') => {
loading.value = true
try {
// TODO: 替换为实际的后端接口地址
const response = await fetch('/api/disaster/list', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
keyword: keyword.trim()
})
})
// 模拟接口响应格式,实际使用时根据后端返回结构调整
// const result = await response.json()
// 模拟异步请求
// if (result.code === 200) {
// list.value = result.data
// emptyText.value = keyword ? '未搜索到相关灾毁信息' : '暂无相关灾毁信息'
// } else {
// showToast(result.message || '获取数据失败')
// list.value = []
// }
// ========== 模拟数据(实际开发时删除此部分) ==========
await new Promise((resolve) => setTimeout(resolve, 500))
const mockData = mockDataJSON
// 模拟后端搜索过滤(实际由后端完成)
if (keyword) {
const filtered = mockData.filter((item) => item.title.toLowerCase().includes(keyword.toLowerCase()))
list.value = filtered
emptyText.value = filtered.length === 0 ? '未搜索到相关灾毁信息' : '暂无相关灾毁信息'
} else {
list.value = mockData
emptyText.value = '暂无相关灾毁信息'
}
// ========== 模拟数据结束 ==========
} catch (error) {
console.error('获取灾毁列表失败:', error)
showToast('获取数据失败,请稍后重试')
list.value = []
} finally {
loading.value = false
}
}
// 搜索处理(调用后端接口)
const handleSearch = () => {
getDisasterList(searchValue.value)
}
// 点击返回
const handleClickBack = () => {
router.push('/')
}
// 点击列表项,跳转详情
const handleClickItem = (item) => {
router.push({
path: '/disaster-detail',
query: {
id: item.id,
title: item.title,
status: item.status,
occurTime: item.occurTime,
estimateRecoverTime: item.estimateRecoverTime,
disasterType: item.disasterType
}
})
}
// 灾毁填报
const handleAdd = () => {
// TODO: 跳转到灾毁填报页面
console.log('点击灾毁填报')
// router.push('/disaster-report')
}
// 页面初始化加载数据
onMounted(() => {
getDisasterList()
})
</script>
<style lang="scss" scoped>
.list-panel {
display: flex;
flex-direction: column;
gap: 8px;
padding-bottom: 80px;
}
/* CardItem 需要设置相对定位 */
:deep(.card-item) {
position: relative;
}
.info-block {
display: flex;
flex-direction: column;
gap: 8px;
padding-right: 24px; /* 为箭头留出空间 */
}
.time-box {
display: flex;
align-items: baseline;
flex-wrap: wrap;
}
.info-label {
font-weight: 400;
font-size: 13px;
color: #999999;
}
.info-value {
font-weight: 400;
font-size: 14px;
color: #333333;
}
/* 使用绝对定位的箭头样式 */
.jump-icon-absolute {
position: absolute;
right: 16px;
top: 50%;
transform: translateY(-50%);
font-size: 16px;
color: rgba(102, 102, 102, 0.4);
cursor: pointer;
}
/* 灾毁类型标签样式 */
.disaster-type-wrapper {
margin-top: 4px;
}
.fab-btn {
position: fixed;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
width: calc(100% - 32px);
max-width: 340px;
border-radius: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
cursor: pointer;
z-index: 10;
&:active {
opacity: 0.9;
transform: translateX(-50%) scale(0.98);
}
}
.loading-wrapper {
display: flex;
justify-content: center;
padding: 40px 0;
}
</style>