502 lines
13 KiB
Vue
502 lines
13 KiB
Vue
<template>
|
|
<div class="container">
|
|
<div class="spacer"></div>
|
|
|
|
<div class="main-content">
|
|
<!-- 积分余额区域 -->
|
|
<div class="balance-section">
|
|
<div class="balance-label">积分余额</div>
|
|
<div class="balance-value">{{ userPoints }}</div>
|
|
<router-link to="/mypoints-history" class="detail-btn">
|
|
<div>点击查看积分明细</div>
|
|
</router-link>
|
|
<img src="/imgs/shop.png" alt="积分商城图标" class="balance-image">
|
|
</div>
|
|
|
|
<!-- 公告区域 -->
|
|
<div class="announcement-section">
|
|
这里是公告内容
|
|
</div>
|
|
|
|
<!-- 空白间隔 -->
|
|
<div class="empty-spacer">
|
|
<router-link to="/shop">
|
|
<button>点击查看全部商品</button>
|
|
</router-link>
|
|
<img src="/imgs/shop2.png" alt="">
|
|
</div>
|
|
|
|
<!-- 分类区域 -->
|
|
<div class="category-section">
|
|
<div class="category-header-container">
|
|
<div class="category-header">分类区</div>
|
|
<div class="category-items-vertical">
|
|
<div
|
|
v-for="category in categories"
|
|
:key="category.id"
|
|
class="category-grid"
|
|
@click="goToCategory(category.id)"
|
|
>
|
|
<div class="category-icon">{{ category.icon }}</div>
|
|
<div class="category-name">{{ category.name }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 右侧商品展示区域 - 修改后的部分 -->
|
|
<div class="product-showcase">
|
|
<router-link to="/shop">
|
|
<div v-if="loading" class="loading-products">
|
|
加载中...
|
|
</div>
|
|
<div v-else class="product-showcase-grid">
|
|
<div class="product-item" v-for="product in featuredProducts" :key="product.id">
|
|
<img :src="product.image" :alt="product.name" class="product-image">
|
|
<div class="product-info">
|
|
<div class="product-name">{{ product.name }}</div>
|
|
<div class="product-price">
|
|
<span class="points">{{ product.rongdou_price }}</span>
|
|
<span class="original-price" v-if="product.originalPoints">{{ product.originalPoints }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- 添加一个空白项来填充剩余空间 -->
|
|
<div class="product-item empty-item" v-if="featuredProducts.length > 0 && featuredProducts.length < 3"></div>
|
|
</div>
|
|
</router-link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { ref, onMounted } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import api from '@/utils/api' // 确保导入正确的api模块
|
|
import { ElMessage } from 'element-plus'
|
|
|
|
import {getImageUrl} from '@/config'
|
|
|
|
export default {
|
|
setup() {
|
|
const router = useRouter()
|
|
const userPoints = ref(0)
|
|
const loading = ref(false)
|
|
|
|
// 分类数据
|
|
const categories = ref([
|
|
{ id: '数码产品', name: '数码产品', icon: '📱' },
|
|
{ id: '图书文具', name: '图书文具', icon: '📚' },
|
|
{ id: '生活用品', name: '生活用品', icon: '🏠' },
|
|
{ id: '食品饮料', name: '食品饮料', icon: '🍔' },
|
|
{ id: '服装配饰', name: '服装配饰', icon: '👕' },
|
|
{ id: '其他', name: '其他', icon: '📦' }
|
|
])
|
|
|
|
// 精选商品数据
|
|
const featuredProducts = ref([])
|
|
|
|
// 获取用户积分
|
|
const getUserPoints = async () => {
|
|
try {
|
|
const {data} = await api.get('/user/points') // 使用api而不是transferAPI
|
|
console.log(data)
|
|
userPoints.value = data.points || 0
|
|
} catch (error) {
|
|
console.error('获取积分信息失败', error)
|
|
ElMessage.error('获取积分信息失败,请稍后重试')
|
|
}
|
|
}
|
|
|
|
// 获取商品列表
|
|
const getProducts = async () => {
|
|
try {
|
|
loading.value = true
|
|
const {data} = await api.get('/products', { // 使用api而不是transferAPI
|
|
params: {
|
|
page: 1,
|
|
limit: 3, // 只获取前3个商品
|
|
sort: 'sales' // 按销量排序获取热门商品
|
|
}
|
|
})
|
|
|
|
// 只取前3个商品作为精选商品
|
|
featuredProducts.value = data.data.products.slice(0, 3)
|
|
featuredProducts.value.forEach(product => {
|
|
if (product.image) {
|
|
product.image = getImageUrl(product.image)
|
|
}
|
|
})
|
|
} catch (error) {
|
|
console.error('获取商品列表失败:', error)
|
|
ElMessage.error('获取商品列表失败')
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
// 跳转到商城对应分类
|
|
const goToCategory = (categoryId) => {
|
|
router.push({
|
|
path: '/shop',
|
|
query: { category: categoryId }
|
|
})
|
|
}
|
|
|
|
onMounted(() => {
|
|
getUserPoints()
|
|
getProducts()
|
|
})
|
|
|
|
return {
|
|
userPoints,
|
|
categories,
|
|
featuredProducts,
|
|
loading,
|
|
getUserPoints,
|
|
goToCategory
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* 使用与主页面一致的容器样式 */
|
|
.container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-height: 100vh;
|
|
width: 100%;
|
|
margin: 0;
|
|
padding: 0;
|
|
background: linear-gradient(to bottom, #ffae00, #f3f3f3);
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
position: relative;
|
|
}
|
|
|
|
.main-content {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 16px;
|
|
gap: 16px;
|
|
max-width: 375px;
|
|
margin: 0 auto;
|
|
width: 100%;
|
|
}
|
|
|
|
.spacer {
|
|
height: 40px;
|
|
}
|
|
|
|
/* 积分余额区域样式 */
|
|
.balance-section {
|
|
width: 343px;
|
|
height: 159px;
|
|
background: rgb(245, 245, 185);
|
|
border-radius: 12px;
|
|
box-shadow: var(--box-shadow);
|
|
padding: 20px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
justify-content: center;
|
|
margin: 0 auto;
|
|
position: relative; /* 为绝对定位提供参考 */
|
|
}
|
|
|
|
.balance-label {
|
|
font-size: 32px; /* 与积分数字相同大小 */
|
|
font-weight: bold; /* 与积分数字相同粗细 */
|
|
color: #666;
|
|
margin-bottom: 8px;
|
|
text-align: left;
|
|
}
|
|
|
|
.balance-value {
|
|
font-size: 32px;
|
|
font-weight: bold;
|
|
color: var(--primary-color);
|
|
margin-bottom: 20px;
|
|
text-align: left;
|
|
width: 100%;
|
|
}
|
|
|
|
.detail-btn {
|
|
width: 123px;
|
|
height: 35px;
|
|
background: #ffde73;
|
|
color: black;
|
|
border: none;
|
|
border-radius: 18px;
|
|
font-size: 14px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
text-decoration: none;
|
|
cursor: pointer;
|
|
transition: var(--transition);
|
|
margin-bottom: 10px; /* 增加底部间距 */
|
|
}
|
|
|
|
.detail-btn:hover {
|
|
background: #c19a6b;
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.balance-image {
|
|
position: absolute; /* 绝对定位 */
|
|
right: 20px; /* 右侧距离 */
|
|
bottom: 20px; /* 底部距离,与按钮底部对齐 */
|
|
height: 150px; /* 增加图片高度 */
|
|
max-width: 120px; /* 增加最大宽度 */
|
|
object-fit: contain; /* 保持图片比例 */
|
|
}
|
|
|
|
/* 公告区域样式 */
|
|
.announcement-section {
|
|
width: 343px;
|
|
height: 46px;
|
|
background: #ffffff;
|
|
border-radius: 12px;
|
|
box-shadow: var(--box-shadow);
|
|
padding: 12px 16px;
|
|
margin: 0 auto;
|
|
display: flex;
|
|
align-items: center;
|
|
font-size: 14px;
|
|
color: #666;
|
|
}
|
|
|
|
/* 空白间隔区域 - 完整样式 */
|
|
.empty-spacer {
|
|
width: 344px;
|
|
height: 71px;
|
|
margin: 0 auto;
|
|
background: white;
|
|
border-radius: 12px;
|
|
box-shadow: var(--box-shadow); /* 增加阴影,与其他区块保持一致 */
|
|
padding: 0 16px; /* 左右内边距,避免内容贴边 */
|
|
display: flex; /* 使用flex布局排列按钮和图片 */
|
|
align-items: center; /* 垂直居中对齐 */
|
|
justify-content: space-between; /* 按钮居左,图片居右 */
|
|
}
|
|
|
|
/* 按钮容器链接样式 */
|
|
.empty-spacer router-link {
|
|
text-decoration: none; /* 去除链接默认下划线 */
|
|
width: auto; /* 宽度由按钮内容决定 */
|
|
}
|
|
|
|
/* 按钮样式优化 */
|
|
.empty-spacer button {
|
|
height: 40px; /* 固定按钮高度,增强点击区域 */
|
|
padding: 0 20px; /* 增加左右内边距,扩大按钮面积 */
|
|
background: linear-gradient(135deg, #ffae00 0%, #ff8c00 100%); /* 渐变背景,呼应顶部色调 */
|
|
color: white; /* 文字白色,提高对比度 */
|
|
border: none; /* 去除默认边框 */
|
|
border-radius: 20px; /* 圆角设计,与页面风格统一 */
|
|
font-size: 15px; /* 适中字体大小 */
|
|
font-weight: 500; /* 半粗体,增强视觉权重 */
|
|
cursor: pointer; /* 鼠标悬停显示手型 */
|
|
transition: var(--transition); /* 过渡动画,与其他交互元素保持一致 */
|
|
box-shadow: 0 2px 4px rgba(255, 140, 0, 0.3); /* 轻微阴影,增强立体感 */
|
|
}
|
|
|
|
/* 按钮悬停效果 */
|
|
.empty-spacer button:hover {
|
|
transform: translateY(-2px); /* 轻微上浮效果 */
|
|
box-shadow: 0 4px 8px rgba(255, 140, 0, 0.4); /* 阴影加深,增强交互反馈 */
|
|
background: linear-gradient(135deg, #ff9a00 0%, #ff7b00 100%); /* 悬停时颜色加深 */
|
|
}
|
|
|
|
/* 按钮:active状态 */
|
|
.empty-spacer button:active {
|
|
transform: translateY(0); /* 点击时恢复原位 */
|
|
box-shadow: 0 1px 2px rgba(255, 140, 0, 0.3); /* 阴影变浅,模拟按压效果 */
|
|
}
|
|
|
|
/* 图片样式优化 */
|
|
.empty-spacer img {
|
|
height: 45px; /* 图片高度略大于按钮,形成视觉平衡 */
|
|
width: auto; /* 宽度自适应,保持比例 */
|
|
object-fit: contain; /* 确保图片完整显示 */
|
|
opacity: 0.9; /* 轻微降低不透明度,避免喧宾夺主 */
|
|
transition: var(--transition); /* 过渡动画 */
|
|
}
|
|
|
|
/* 图片悬停效果(可选) */
|
|
.empty-spacer img:hover {
|
|
opacity: 1; /* 悬停时恢复完全不透明度 */
|
|
transform: scale(1.05); /* 轻微放大,增强交互感 */
|
|
}
|
|
|
|
/* 分类区域样式 */
|
|
.category-section {
|
|
width: 343px;
|
|
height: auto; /* 改为自适应高度 */
|
|
background: white;
|
|
border-radius: 12px;
|
|
box-shadow: var(--box-shadow);
|
|
padding: 16px;
|
|
margin: 0 auto;
|
|
display: flex; /* 添加flex布局 */
|
|
gap: 16px; /* 添加间距 */
|
|
}
|
|
|
|
.category-header-container {
|
|
width: 114px; /* 保持原有宽度 */
|
|
display: flex;
|
|
flex-direction: column; /* 改为垂直布局 */
|
|
padding-right: 16px;
|
|
border-right: 1px solid #f0f0f0;
|
|
}
|
|
|
|
.category-header {
|
|
width: 100%;
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
color: var(--dark-color);
|
|
padding: 16px;
|
|
background-color: #cae5ff;
|
|
border-radius: 8px;
|
|
margin-bottom: 16px; /* 增加与分类项的间距 */
|
|
}
|
|
|
|
.category-items-vertical {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px; /* 调整分类项间距 */
|
|
}
|
|
|
|
.category-grid {
|
|
width: 100%;
|
|
background-color: #fff0d0;
|
|
border-radius: 8px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
padding: 8px 12px;
|
|
}
|
|
|
|
.category-grid:hover {
|
|
background-color: #ffe4b3;
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.category-icon {
|
|
font-size: 20px; /* 稍微调小图标 */
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.category-name {
|
|
font-size: 12px; /* 稍微调小字体 */
|
|
font-weight: 500;
|
|
color: var(--dark-color);
|
|
text-align: center;
|
|
}
|
|
|
|
/* 右侧商品展示区域 */
|
|
.product-showcase {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.product-showcase-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr;
|
|
gap: 16px;
|
|
height: 100%;
|
|
}
|
|
|
|
.product-item {
|
|
background: #fff;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
transition: all 0.3s ease;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.empty-item {
|
|
visibility: hidden; /* 隐藏空白项但保留其空间 */
|
|
}
|
|
|
|
.product-item:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
}
|
|
|
|
.product-image {
|
|
width: 100%;
|
|
height: 100px;
|
|
object-fit: cover;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.product-info {
|
|
padding: 8px;
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.product-name {
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
margin: 0 0 4px 0;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.product-price {
|
|
margin-top: auto; /* 将价格推到底部 */
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.points {
|
|
color: #ff6b35;
|
|
font-weight: 600;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.original-price {
|
|
color: #999;
|
|
font-size: 12px;
|
|
text-decoration: line-through;
|
|
}
|
|
|
|
/* 使用与主页面一致的变量 */
|
|
:root {
|
|
--primary-color: #4361ee;
|
|
--secondary-color: #3f37c9;
|
|
--accent-color: #4895ef;
|
|
--light-color: #f8f9fa;
|
|
--dark-color: #212529;
|
|
--success-color: #4cc9f0;
|
|
--warning-color: #f8961e;
|
|
--danger-color: #f72585;
|
|
--border-radius: 12px;
|
|
--box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
--transition: all 0.3s ease;
|
|
}
|
|
|
|
.loading-products {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
height: 100px;
|
|
color: #666;
|
|
}
|
|
</style> |