Files
pj_h5_cloud/src/pages/integrated/lostAndFound/index.vue
T

244 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.
<template>
<view class="container">
<view class="custom-nav">
<view class="nav-back" @tap="goBack">
<text class="back-arrow">←</text>
</view>
<view class="nav-title">失物招领</view>
</view>
<scroll-view
scroll-y
class="scroll-view"
@scrolltolower="onLoadMore"
refresher-enabled
:refresher-triggered="refreshing"
@refresherrefresh="onRefresh"
>
<view v-if="list.length > 0">
<view
v-for="item in list"
:key="item.id"
class="item-card"
@tap="viewDetail(item)"
>
<view class="item-title">{{ item.title }}</view>
<view class="item-description" v-html="item.description"></view>
<view class="item-info">
<text>地点:{{ item.location }}</text>
<text>时间:{{ formatDate(item.dateFound) }}</text>
</view>
<view :class="['status-tag', item.status === '0' ? 'status-pending' : 'status-claimed']">
{{ item.status === '0' ? '待认领' : '已认领' }}
</view>
</view>
</view>
<view v-else class="empty-box">
<text class="empty-text">暂无失物招领信息</text>
</view>
<view v-if="loading" class="loading">加载中...</view>
<view v-if="!hasMore && list.length > 0" class="no-more">没有更多了</view>
</scroll-view>
</view>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import dayjs from 'dayjs'
import lostAndFoundApi from '@/sheep/api/lostAndFound'
interface LostAndFoundItem {
id: string
title: string
picUrl: string | null
description: string
dateFound: string
location: string
status: string
}
interface ApiResponse {
code: number
data: {
records: LostAndFoundItem[]
pages: number
}
}
const list = ref<LostAndFoundItem[]>([])
const current = ref(1)
const hasMore = ref(true)
const loading = ref(false)
const refreshing = ref(false)
const fetchData = async (page: number = 1) => {
try {
loading.value = true
const response = await lostAndFoundApi.getList({
current: page,
size: 10,
}) as unknown as ApiResponse
if (response.code === 0 && response.data) {
if (page === 1) {
list.value = response.data.records
} else {
list.value = [...list.value, ...response.data.records]
}
hasMore.value = page < response.data.pages
current.value = page
}
} catch (error) {
console.error('Failed to fetch lost and found items:', error)
} finally {
loading.value = false
refreshing.value = false
}
}
const onLoadMore = () => {
if (!loading.value && hasMore.value) {
fetchData(current.value + 1)
}
}
const onRefresh = async () => {
refreshing.value = true
await fetchData(1)
}
const viewDetail = (item: LostAndFoundItem) => {
if (!item?.id) return
uni.navigateTo({
url: `/pages/integrated/lostAndFound/detail?id=${item.id}`,
success: (res) => {
res.eventChannel.emit('initDetail', item)
},
})
}
const formatDate = (date: string) => {
return dayjs(date).format('YYYY-MM-DD')
}
const goBack = () => {
uni.navigateBack()
}
onMounted(() => {
fetchData()
})
</script>
<style lang="less" scoped>
.container {
min-height: 100vh;
background-color: #f5f5f5;
}
.custom-nav {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 88rpx;
background-color: #1777FF;
display: flex;
align-items: center;
padding: 0 30rpx;
z-index: 100;
}
.nav-back {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
}
.back-arrow {
color: #fff;
font-size: 40rpx;
font-weight: bold;
}
.nav-title {
flex: 1;
text-align: center;
color: #fff;
font-size: 32rpx;
font-weight: 500;
margin-right: 60rpx; // 为了保持标题居中,抵消返回按钮的宽度
}
.scroll-view {
height: calc(100vh - 88rpx);
margin-top: 88rpx;
box-sizing: border-box;
}
.item-card {
margin: 12px;
padding: 16px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.item-title {
font-size: 16px;
font-weight: 500;
color: #333;
margin-bottom: 8px;
}
.item-description {
font-size: 14px;
color: #666;
margin-bottom: 8px;
}
.item-info {
display: flex;
gap: 16px;
color: #999;
font-size: 12px;
margin-bottom: 8px;
}
.status-tag {
display: inline-block;
padding: 2px 8px;
border-radius: 4px;
font-size: 12px;
}
.status-pending {
background-color: #e6f7ff;
color: #1890ff;
}
.status-claimed {
background-color: #f6ffed;
color: #52c41a;
}
.empty-box {
display: flex;
justify-content: center;
align-items: center;
height: 200px;
}
.empty-text {
color: #999;
font-size: 14px;
}
.loading, .no-more {
text-align: center;
padding: 12px;
color: #999;
font-size: 12px;
}
</style>