Files
WAI_Project_UNIX/pages/adoption/detail.uvue
2026-01-21 01:37:34 +08:00

231 lines
4.9 KiB
Plaintext

<template>
<cl-page>
<cl-topbar title="项目详情" />
<scroll-view scroll-y class="content" v-if="project != null">
<swiper class="banner" autoplay circular indicator-dots>
<swiper-item v-for="(img, index) in projectImages" :key="index">
<image class="banner-image" :src="img" mode="aspectFill" />
</swiper-item>
</swiper>
<view class="project-info">
<text class="project-name">{{ project.name }}</text>
<view class="project-meta">
<view class="meta-item">
<text class="meta-label">周期</text>
<text class="meta-value">{{ project.duration }}天</text>
</view>
<view class="meta-item">
<text class="meta-label">权益</text>
<text class="meta-value">{{ benefits.length }}项</text>
</view>
<view class="meta-item">
<text class="meta-label">已认养</text>
<text class="meta-value">{{ project.adoptedCount }}人</text>
</view>
</view>
</view>
<view class="benefits-section">
<text class="section-title">认养权益</text>
<view class="benefit-list">
<view v-for="(benefit, index) in benefits" :key="index" class="benefit-item">
<cl-icon name="check-circle" :size="36" color="#52c41a" />
<text class="benefit-text">{{ benefit }}</text>
</view>
</view>
</view>
<view class="desc-section">
<text class="section-title">项目介绍</text>
<text class="desc">{{ project.description }}</text>
</view>
<view style="height: 140rpx;"></view>
</scroll-view>
<view class="bottom-bar" v-if="project != null">
<view class="price-info">
<text class="price">¥{{ project.price }}</text>
<text class="original" v-if="project.originalPrice != null">¥{{ project.originalPrice }}</text>
</view>
<cl-button type="primary" round @click="onAdopt">立即认养</cl-button>
</view>
</cl-page>
</template>
<script setup lang="uts">
import { ref, computed, onMounted } from 'vue';
import { router, useCool, parseObject } from '@/cool';
const { service } = useCool();
const project = ref<any>(null);
const projectImages = computed(() => {
if (project.value?.images == null) return ['/static/images/farm.png'];
try {
return parseObject<string[]>(project.value.images) ?? ['/static/images/farm.png'];
} catch {
return ['/static/images/farm.png'];
}
});
const benefits = computed(() => {
if (project.value?.benefits == null) return ['新鲜农产品直送', '专属认养证书', '实时生长查看'];
try {
return parseObject<string[]>(project.value.benefits) ?? ['新鲜农产品直送', '专属认养证书', '实时生长查看'];
} catch {
return ['新鲜农产品直送', '专属认养证书', '实时生长查看'];
}
});
async function loadProject() {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const projectId = Number(currentPage.options?.id || 0);
if (projectId != 0) {
try {
const res = await service.nongchuang.adoption.detail({ id: projectId });
project.value = res;
} catch (e) {
project.value = {
id: projectId,
name: '有机苹果园认养',
description: '位于山东烟台的优质苹果园,采用有机种植方式',
duration: 180,
price: 299,
adoptedCount: 56
};
}
}
}
function onAdopt() {
uni.showToast({ title: '认养功能开发中', icon: 'none' });
}
onMounted(() => {
loadProject();
});
</script>
<style lang="scss" scoped>
.content {
flex: 1;
}
.banner {
height: 400rpx;
.banner-image {
width: 100%;
height: 100%;
}
}
.project-info {
padding: 30rpx;
background: #fff;
.project-name {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
.project-meta {
display: flex;
flex-direction: row;
justify-content: space-around;
margin-top: 30rpx;
padding: 24rpx 0;
background: #f9f9f9;
border-radius: 12rpx;
.meta-item {
text-align: center;
.meta-label {
font-size: 24rpx;
color: #999;
}
.meta-value {
font-size: 28rpx;
color: #333;
font-weight: bold;
margin-top: 8rpx;
}
}
}
}
.benefits-section, .desc-section {
margin-top: 20rpx;
padding: 30rpx;
background: #fff;
.section-title {
font-size: 30rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
}
}
.benefit-list {
.benefit-item {
display: flex;
flex-direction: row;
align-items: center;
padding: 16rpx 0;
font-size: 28rpx;
color: #666;
.benefit-text {
margin-left: 16rpx;
}
}
}
.desc {
font-size: 28rpx;
color: #666;
line-height: 1.6;
}
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 30rpx;
background: #fff;
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.06);
.price-info {
display: flex;
flex-direction: row;
align-items: center;
.price {
font-size: 40rpx;
font-weight: bold;
color: #ff4d4f;
}
.original {
font-size: 24rpx;
color: #999;
margin-left: 10rpx;
}
}
}
</style>