Files
jurong_circle_frontdesk/src/views/ProductSummary.vue

403 lines
9.0 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>
<!-- 头部 -->
<div class="header">
<span @click="$router.go(-1)"><返回</span>
<el-icon @click="$router.push(`/product/${firstProduct.id}`)"><ShoppingCart /></el-icon>
</div>
<div class="products-container">
<div class="product-card">
<div class="product-image">
<el-carousel
:interval="4000"
indicator-position="outside"
style="min-height: 300px;"
>
<el-carousel-item v-for="(image, index) in firstProduct.images" :key="index">
<img :src="image" :alt="firstProduct.name" class="carousel-image" />
</el-carousel-item>
</el-carousel>
</div>
<div class="product-details">
<img :src="firstProduct.image" :alt="firstProduct.name" class="small-image" />
<div class="product-info">
<span class="product-name">{{ firstProduct.name }}</span>
<span class="product-price">{{ firstProduct.points }} 积分</span>
</div>
<span @click="$router.push(`/product/${firstProduct.id}`)" class="link">详情></span>
</div>
<div class="action">
<button class="button" @click="$router.push(`/product/${firstProduct.id}`)">立即购买</button>
</div>
</div>
<div v-for="product in products" :key="product.id" class="product-card">
<!-- 轮播图部分 -->
<div class="product-image">
<el-carousel
:interval="4000"
indicator-position="outside"
style="min-height: 300px;"
>
<el-carousel-item v-for="(image, index) in product.images" :key="index">
<img :src="image" :alt="product.name" class="carousel-image" />
</el-carousel-item>
</el-carousel>
</div>
<div class="product-details">
<img :src="product.image" :alt="product.name" class="small-image" />
<div class="product-info">
<span class="product-name">{{ product.name }}</span>
<span class="product-price">{{ product.points }} 积分</span>
</div>
<span @click="$router.push(`/product/${product.id}`)" class="link">详情></span>
</div>
<div class="action">
<button class="button" @click="$router.push(`/product/${product.id}`)">立即购买</button>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import api from '@/utils/api'
import { useRoute, useRouter } from 'vue-router'
import {ElMessage} from "element-plus";
import {Bottom, ShoppingCart} from "@element-plus/icons-vue";
const products = ref([])
const firstProduct = ref([])
const route = useRoute()
const productId = ref(null)
const getProducts = async () => {
try {
const { data } = await api.get('/products', {
params: {
page: 1,
limit: 20,
category: '',
keyword: '',
sort: ''
}
})
console.log('API 响应数据:', data)
// 根据你的 API 响应结构调整这里
if (data.data && data.data.products) {
products.value = data.data.products
}
else if (Array.isArray(data.products)) {
products.value = data.products
}
else if (Array.isArray(data)) {
products.value = data
}
else {
console.error('无法解析的商品数据格式:', data)
}
console.log('解析后的商品数据:', products.value)
} catch (error) {
console.error('获取商品失败:', error)
console.error('错误详情:', error.response?.data)
}
}
const getFirstProduct = async () => {
try {
const productId = route.params.id
const [productRes] = await Promise.all([
api.get(`/products/${productId}`)
])
console.log(productRes,'productRes');
firstProduct.value = productRes.data.data.product
} catch (error) {
ElMessage.error('获取商品详情失败')
console.log(error)
}
}
// 添加生命周期钩子来调用函数
onMounted(() => {
productId.value = route.params.id
console.log('Product ID:', productId.value)
getProducts()
getFirstProduct()
})
</script>
<style scoped>
.header {
/* 基础布局 */
padding: 16px 20px;
background-color: #ffffff;
border-bottom: 1px solid #f0f0f0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
/* 固定在顶部 */
position: sticky;
top: 0;
z-index: 100;
/* 内容居中 */
display: flex;
align-items: center;
justify-content: space-between; /* 添加此项使内容分布在两端 */
}
.button {
background: #ff7700;
color: white;
border: none;
padding: 12px 24px;
border-radius: 6px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 6px rgba(50, 142, 240, 0.2);
width: 50%;
margin: 12px auto 0; /* 修改这里上下12px左右自动居中 */
display: block; /* 添加此项使margin: auto生效 */
}
.button:hover {
background: linear-gradient(135deg, #337ecc, #2a6db3);
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(50, 142, 240, 0.3);
}
.button:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(50, 142, 240, 0.2);
}
.header span {
/* 返回按钮样式 */
color: #333333;
font-size: 16px;
font-weight: 500;
cursor: pointer;
padding: 6px 10px;
border-radius: 6px;
transition: all 0.2s ease;
/* 添加返回图标占位 */
display: inline-flex;
align-items: center;
gap: 6px;
}
.products-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
padding: 20px;
background: linear-gradient(to bottom, #ffae00, #f3f3f3);
}
.product-card {
border: 1px solid #e0e0e0;
border-radius: 12px;
padding: 16px;
background: white;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
transition: all 0.3s ease;
overflow: hidden;
width: 374px;
min-height: 526px;
display: flex;
flex-direction: column; /* 改为垂直布局 */
}
.product-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 16px rgba(0,0,0,0.15);
}
.product-image {
position: relative;
margin-bottom: 12px;
border-radius: 8px;
overflow: hidden;
/* 关键:添加底部内边距,容纳指示器 */
padding-bottom: 30px;
min-height: 300px; /* 保留轮播图最小高度 */
}
.carousel-image {
width: 100%;
height: 100%;
object-fit: contain; /* 完整显示图片,不裁剪 */
background-color: #f5f5f5; /* 空白处用浅灰色填充,避免白屏 */
}
/* 修改部分开始 */
.product-details {
display: flex;
align-items: flex-start;
gap: 12px;
text-align: left;
margin-top: auto; /* 推到卡片底部 */
padding-top: 12px; /* 添加顶部间距 */
border-top: 1px solid #f0f0f0; /* 可选:添加分隔线 */
}
.small-image {
width: 60px;
height: 60px;
object-fit: cover;
border-radius: 8px;
border: 2px solid #f0f0f0;
flex-shrink: 0;
}
.product-info {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 60px;
flex-grow: 1;
min-width: 0;
}
.product-name {
font-size: 16px;
font-weight: 600;
color: #333;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
margin-bottom: 0;
width: 200px;
}
.product-price {
color: #e53935;
font-weight: bold;
font-size: 18px;
display: flex;
align-items: center;
gap: 4px;
}
/* 修改部分结束 */
/* 轮播图样式调整 */
:deep(.el-carousel) {
border-radius: 8px;
}
:deep(.el-carousel__container) {
border-radius: 8px;
}
:deep(.el-carousel__indicators) {
bottom: 10px; /* 从 -25px 改为 10px放在轮播图底部内侧 */
z-index: 10; /* 确保指示器在图片上方显示 */
}
:deep(.el-carousel__button) {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #ccc;
}
:deep(.el-carousel__indicator.is-active .el-carousel__button) {
background-color: #409eff;
}
/* 响应式设计 */
@media (max-width: 768px) {
.products-container {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
padding: 16px;
}
.product-card {
padding: 12px;
min-height: 450px; /* 移动端最小高度适配 */
width: 100%; /* 移动端卡片宽度占满父容器,避免超出屏幕 */
}
.product-image {
padding-bottom: 75%;
min-height: 200px; /* 移动端轮播图最小高度 */
}
/* 响应式调整 */
.product-details {
gap: 10px;
}
.small-image {
width: 50px;
height: 50px;
}
.product-info {
height: 50px;
}
.product-name {
font-size: 14px;
}
.product-price {
font-size: 16px;
}
}
@media (max-width: 480px) {
.products-container {
grid-template-columns: repeat(1, 1fr);
gap: 12px;
padding: 12px;
}
.product-card {
padding: 10px;
}
.product-image {
height: 200px;
}
/* 响应式调整 */
.product-details {
gap: 8px;
}
.small-image {
width: 45px;
height: 45px;
}
.product-info {
height: 45px;
}
.product-name {
font-size: 13px;
}
.product-price {
font-size: 15px;
}
}
</style>