application [cat-mini-app] view page [pages/cats] development

This commit is contained in:
NVWA Code Agent
2025-12-11 16:42:32 +00:00
parent e32dd8d0c1
commit eacb2a8f28
2 changed files with 301 additions and 0 deletions

View File

@@ -23,6 +23,12 @@
"style": {
"navigationBarTitleText": "种公种母介绍"
}
},
{
"path": "pages/cats",
"style": {
"navigationBarTitleText": "猫咪情况"
}
}
],
"globalStyle": {

View File

@@ -0,0 +1,295 @@
<template>
<view class="cats-page">
<!-- 列表模式 -->
<view v-if="!detailId" class="cats-list">
<uni-list>
<uni-list-item v-for="cat in cats" :key="cat.id" :show-arrow="true" @click="goToDetail(cat.id)">
<view class="cat-item">
<view class="cat-image">
<image v-if="cat.images && cat.images.length > 0" :src="cat.images[0].url" mode="aspectFit" />
<view v-else class="no-image">暂无图片</view>
</view>
<view class="cat-info">
<view class="cat-name">{{ cat.name }}</view>
<view class="cat-details">
年龄: {{ getAgeString(cat.age) }} |
等级: {{ cat.grade }} |
性别: {{ cat.gender === 'male' ? '公' : '母' }} |
类型: {{ getTypeString(cat.type) }} |
状态: {{ cat.is_available ? '可售卖' : '不可售卖' }}
</view>
<view v-if="cat.description" class="cat-description">{{ cat.description }}</view>
</view>
</view>
</uni-list-item>
</uni-list>
<view class="pagination">
<uni-pagination
v-model="currentPage"
:total="totalCats"
:page-size="pageSize"
@change="onPageChange"
/>
</view>
</view>
<!-- 详情模式 -->
<view v-else class="cat-detail">
<view v-if="currentCat">
<view class="cat-header">
<view class="cat-name">{{ currentCat.name }}</view>
<view class="cat-status">
<uni-tag :text="currentCat.is_available ? '可售卖' : '不可售卖'" :type="currentCat.is_available ? 'success' : 'error'" />
</view>
</view>
<view class="cat-images">
<image v-for="image in currentCat.images" :key="image.id" :src="image.url" mode="aspectFit" />
</view>
<view class="cat-details">
<view>年龄: {{ getAgeString(currentCat.age) }}</view>
<view>等级: {{ currentCat.grade }}</view>
<view>性别: {{ currentCat.gender === 'male' ? '公' : '母' }}</view>
<view>类型: {{ getTypeString(currentCat.type) }}</view>
<view v-if="currentCat.description">描述: {{ currentCat.description }}</view>
</view>
</view>
<view v-else>加载中...</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { entities } from '@/lib/nvwa'
import type { Cat } from '@/types/cat' // 假设有类型定义
const detailId = ref<number | null>(null)
const cats = ref<Cat[]>([])
const currentCat = ref<Cat | null>(null)
const currentPage = ref(1)
const pageSize = ref(10)
const totalCats = ref(0)
const getAgeString = (ageInMonths: number) => {
const years = Math.floor(ageInMonths / 12)
const months = ageInMonths % 12
if (years > 0) {
return `${years}${months}个月`
}
return `${months}个月`
}
const getTypeString = (type: string) => {
const typeMap = {
breeding_male: '种公',
breeding_female: '种母',
kitten: '幼猫'
}
return typeMap[type] || type
}
const loadCats = async (page: number) => {
try {
const offset = (page - 1) * pageSize.value
const { data, error } = await entities
.from('cat')
.select('id, name, age, gender, grade, type, is_available, description, image_ids')
.range(offset, offset + pageSize.value - 1)
if (error) {
console.error('Error loading cats:', error)
return
}
cats.value = data || []
// 加载图片信息
for (const cat of cats.value) {
if (cat.image_ids && cat.image_ids.length > 0) {
const { data: images } = await entities
.from('nvwa_attribute_file')
.select('id, url')
.in('id', cat.image_ids)
cat.images = images || []
} else {
cat.images = []
}
}
// 获取总数
const { count } = await entities
.from('cat')
.select('*', { count: 'exact', head: true })
totalCats.value = count || 0
} catch (e) {
console.error('Failed to load cats:', e)
}
}
const loadCatDetail = async (id: number) => {
try {
const { data, error } = await entities
.from('cat')
.select('id, name, age, gender, grade, type, is_available, description, image_ids')
.eq('id', id)
.single()
if (error) {
console.error('Error loading cat detail:', error)
return
}
currentCat.value = data
// 加载图片
if (currentCat.value.image_ids && currentCat.value.image_ids.length > 0) {
const { data: images } = await entities
.from('nvwa_attribute_file')
.select('id, url')
.in('id', currentCat.value.image_ids)
currentCat.value.images = images || []
} else {
currentCat.value.images = []
}
} catch (e) {
console.error('Failed to load cat detail:', e)
}
}
const goToDetail = (id: number) => {
uni.navigateTo({
url: `/pages/cats?id=${id}`
})
}
const onPageChange = (page: number) => {
currentPage.value = page
loadCats(page)
}
onMounted(() => {
const pages = getCurrentPages()
const currentPageInstance = pages[pages.length - 1]
const query = currentPageInstance.$page.options || {}
if (query.id) {
detailId.value = parseInt(query.id as string)
loadCatDetail(detailId.value)
} else {
const page = parseInt(query.page as string) || 1
currentPage.value = page
loadCats(page)
}
})
</script>
<style scoped>
.cats-page {
background-color: #f8f8f8;
min-height: 100vh;
}
.cats-list {
padding: 10px;
}
.cat-item {
display: flex;
align-items: center;
padding: 10px;
background-color: white;
border-radius: 8px;
margin-bottom: 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.cat-image {
width: 80px;
height: 80px;
margin-right: 10px;
border-radius: 8px;
overflow: hidden;
background-color: #eee;
display: flex;
align-items: center;
justify-content: center;
}
.cat-image image {
width: 100%;
height: 100%;
}
.no-image {
font-size: 12px;
color: #999;
}
.cat-info {
flex: 1;
}
.cat-name {
font-weight: bold;
font-size: 16px;
margin-bottom: 5px;
}
.cat-details {
font-size: 12px;
color: #666;
margin-bottom: 5px;
}
.cat-description {
font-size: 12px;
color: #999;
}
.pagination {
padding: 20px;
display: flex;
justify-content: center;
}
.cat-detail {
padding: 20px;
}
.cat-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.cat-name {
font-size: 24px;
font-weight: bold;
}
.cat-images {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 20px;
}
.cat-images image {
width: 100px;
height: 100px;
border-radius: 8px;
}
.cat-details {
background-color: white;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.cat-details view {
margin-bottom: 10px;
font-size: 14px;
}
</style>