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

270 lines
5.7 KiB
Plaintext

<template>
<cl-page>
<custom-back />
<scroll-view scroll-y class="content" v-if="product != null">
<swiper class="banner" autoplay circular indicator-dots>
<swiper-item v-for="(img, index) in productImages" :key="index">
<image class="banner-image" :src="img" mode="aspectFill" />
</swiper-item>
</swiper>
<view class="product-info">
<view class="price-row">
<text class="price">¥{{ product.price }}</text>
<text class="original-price" v-if="product.originalPrice != null">¥{{ product.originalPrice }}</text>
<text class="sales">已售{{ product.salesCount != null ? product.salesCount : 0 }}件</text>
</view>
<text class="product-name">{{ product.name }}</text>
<text class="product-origin" v-if="product.origin != null">产地: {{ product.origin }}</text>
</view>
<view class="spec-section">
<view class="spec-row">
<text class="spec-label">规格</text>
<text class="spec-value">{{ selectedSpec.length > 0 ? selectedSpec : '请选择' }}</text>
<cl-icon name="arrow-right" :size="28" color="#999" />
</view>
</view>
<view class="detail-section">
<text class="section-title">商品详情</text>
<rich-text class="detail-content" :nodes="product.detail != null ? product.detail : '暂无详情'"></rich-text>
</view>
<view style="height: 140rpx;"></view>
</scroll-view>
<view class="bottom-bar" v-if="product != null">
<view class="action-btns">
<view class="action-item" @click="goCart">
<cl-icon name="shopping-cart" :size="44" color="#666" />
<text class="action-text">购物车</text>
</view>
</view>
<view class="buy-btns">
<cl-button class="btn-cart" type="warning" round @click="addToCart">加入购物车</cl-button>
<cl-button class="btn-buy" type="primary" round @click="buyNow">立即购买</cl-button>
</view>
</view>
</cl-page>
</template>
<script setup lang="uts">
import { ref, computed, onMounted } from 'vue';
import { router, useCool, parseObject } from '@/cool';
import CustomBack from '@/components/custom-back.uvue';
const { service } = useCool();
const product = ref<any>(null);
const selectedSpec = ref('');
const productImages = computed(() : string[] => {
if (product.value == null) return ['/static/images/product.png'];
const p = product.value as UTSJSONObject;
const mainImage = p.getString('mainImage') != null ? p.getString('mainImage') : '/static/images/product.png';
if (p.get('images') == null) return [mainImage as string];
try {
const images = parseObject<string[]>(p.get('images') as string);
return images != null ? images : [mainImage as string];
} catch {
return [mainImage as string];
}
});
async function loadProduct() {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const productId = Number(currentPage.options != null && currentPage.options!['id'] != null ? currentPage.options!['id'] : 0);
if (productId != 0) {
try {
const res = await service.nongchuang.product.detail({ id: productId });
product.value = res;
} catch (e) {
product.value = {
id: productId,
name: '有机番茄',
price: 9.9,
originalPrice: 15.9,
salesCount: 128,
origin: '山东寿光',
detail: '新鲜有机番茄,当日采摘'
};
}
}
}
function goCart() {
router.push({ path: '/pages/mall/cart' });
}
async function addToCart() {
if (product.value == null) return;
try {
await service.nongchuang.cart.add({ productId: product.value.id, quantity: 1 });
uni.showToast({ title: '已加入购物车', icon: 'success' });
} catch (e: any) {
const msg = e.message;
uni.showToast({ title: msg != null ? msg : '添加失败', icon: 'none' });
}
}
function buyNow() {
uni.showToast({ title: '购买功能开发中', icon: 'none' });
}
onMounted(() => {
loadProduct();
});
</script>
<style lang="scss" scoped>
.content {
flex: 1;
}
.banner {
height: 500rpx;
.banner-image {
width: 100%;
height: 100%;
}
}
.product-info {
padding: 30rpx;
background: #fff;
.price-row {
display: flex;
flex-direction: row;
align-items: flex-end;
.price {
font-size: 44rpx;
font-weight: bold;
color: #ff4d4f;
margin-right: 16rpx;
}
.original-price {
font-size: 28rpx;
color: #999;
}
.sales {
font-size: 24rpx;
color: #999;
margin-left: auto;
}
}
.product-name {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-top: 16rpx;
}
.product-origin {
font-size: 26rpx;
color: #999;
margin-top: 10rpx;
}
}
.spec-section {
margin-top: 20rpx;
background: #fff;
.spec-row {
display: flex;
flex-direction: row;
align-items: center;
padding: 24rpx 30rpx;
.spec-label {
font-size: 28rpx;
color: #333;
}
.spec-value {
flex: 1;
text-align: right;
font-size: 28rpx;
color: #999;
margin-right: 10rpx;
}
}
}
.detail-section {
margin-top: 20rpx;
padding: 30rpx;
background: #fff;
.section-title {
font-size: 30rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
}
.detail-content {
font-size: 28rpx;
color: #666;
line-height: 1.6;
}
}
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
flex-direction: row;
align-items: center;
padding: 16rpx 20rpx;
background: #fff;
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.06);
.action-btns {
display: flex;
flex-direction: row;
padding-right: 30rpx;
.action-item {
margin-right: 30rpx;
display: flex;
flex-direction: column;
align-items: center;
.action-text {
font-size: 20rpx;
color: #666;
}
}
}
.buy-btns {
flex: 1;
display: flex;
flex-direction: row;
.btn-cart {
flex: 1;
margin-right: 16rpx;
}
.btn-buy {
flex: 1;
}
}
}
</style>