482 lines
11 KiB
Vue
482 lines
11 KiB
Vue
<template>
|
||
<view class="container">
|
||
<!-- 顶部搜索框 -->
|
||
<view class="search-container">
|
||
<view class="search-box">
|
||
<uni-icons type="search" size="16" color="#999"></uni-icons>
|
||
<input class="search-input" placeholder="请输入关键词搜索" />
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 轮播图 -->
|
||
<view class="banner-container" v-if="banners.length > 0">
|
||
<swiper class="banner-swiper" indicator-dots="true" autoplay="true" interval="3000" duration="500">
|
||
<swiper-item v-for="banner in banners" :key="banner.id" @click="onBannerClick(banner)">
|
||
<view class="banner-item">
|
||
<image class="banner-image" :src="getFullImageUrl(banner.image_url)" mode="aspectFill"></image>
|
||
<!-- <view class="banner-content" v-if="banner.title || banner.description">
|
||
<text class="banner-title" v-if="banner.title">{{ banner.title }}</text>
|
||
<text class="banner-description" v-if="banner.description">{{ banner.description }}</text>
|
||
</view> -->
|
||
</view>
|
||
</swiper-item>
|
||
</swiper>
|
||
</view>
|
||
|
||
<!-- 分类导航 -->
|
||
<view class="category-container" v-if="categories.length > 0">
|
||
<swiper class="category-swiper" indicator-dots="true" v-if="categoryPages.length > 1">
|
||
<swiper-item v-for="(page, pageIndex) in categoryPages" :key="pageIndex">
|
||
<view class="category-grid">
|
||
<view class="category-row" v-for="(row, rowIndex) in page" :key="rowIndex">
|
||
<view class="category-item" v-for="category in row" :key="category.id" @click="navigateToCategory(category.id)">
|
||
<image v-if="category.category_icon" class="category-icon" :src="getFullImageUrl(category.category_icon)" mode="aspectFit"></image>
|
||
<uni-icons v-else type="apps" size="40" color="#FF4444"></uni-icons>
|
||
<text class="category-text">{{ category.category_name }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</swiper-item>
|
||
</swiper>
|
||
<!-- 如果只有一页分类,不显示swiper -->
|
||
<view class="category-grid" v-else-if="categoryPages.length === 1">
|
||
<view class="category-row" v-for="(row, rowIndex) in categoryPages[0]" :key="rowIndex">
|
||
<view class="category-item" v-for="category in row" :key="category.id" @click="navigateToCategory(category.id)">
|
||
<image v-if="category.category_icon" class="category-icon" :src="getFullImageUrl(category.category_icon)" mode="aspectFit"></image>
|
||
<uni-icons v-else type="apps" size="40" color="#FF4444"></uni-icons>
|
||
<text class="category-text">{{ category.category_name }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 一级商品列表 -->
|
||
<view class="product-section" v-if="primaryProducts.length > 0">
|
||
<view class="section-header">
|
||
<text class="section-title">热门商品</text>
|
||
<text class="view-all" @click="viewAllProducts">查看全部></text>
|
||
</view>
|
||
<view class="product-grid">
|
||
<view class="product-item" v-for="product in displayProducts" :key="product.id" @click="navigateToProduct(product.id)">
|
||
<view class="product-image-container">
|
||
<image v-if="product.product_images"
|
||
:src="getFullImageUrl(getFirstImage(product.product_images))"
|
||
mode="aspectFill"
|
||
class="product-image"></image>
|
||
<view v-else class="default-image">
|
||
<uni-icons type="image" size="60" color="#ccc"></uni-icons>
|
||
</view>
|
||
</view>
|
||
<view class="product-info">
|
||
<text class="product-name">{{ product.product_name }}</text>
|
||
<text class="product-description">{{ product.product_description }}</text>
|
||
<view class="product-price">
|
||
<text class="current-price">¥{{ product.current_price }}</text>
|
||
<text class="original-price" v-if="product.original_price > product.current_price">¥{{ product.original_price }}</text>
|
||
</view>
|
||
<view class="product-stats">
|
||
<text class="stats-text">销量 {{ product.sales_count }}</text>
|
||
<text class="stats-text">库存 {{ product.stock_quantity }}</text>
|
||
<!-- <text class="stats-text">浏览 {{ product.view_count }}</text> -->
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import request from '@/utils/request.js'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
banners: [],
|
||
categories: [],
|
||
primaryProducts: [],
|
||
token: ''
|
||
}
|
||
},
|
||
onLoad() {
|
||
this.checkLogin()
|
||
this.loadData()
|
||
},
|
||
computed: {
|
||
// 将分类按每页8个分组,用于滑动分页
|
||
categoryPages() {
|
||
const pages = []
|
||
for (let i = 0; i < this.categories.length; i += 8) {
|
||
const pageCategories = this.categories.slice(i, i + 8)
|
||
// 每页内部按每行4个分组
|
||
const rows = []
|
||
for (let j = 0; j < pageCategories.length; j += 4) {
|
||
rows.push(pageCategories.slice(j, j + 4))
|
||
}
|
||
pages.push(rows)
|
||
}
|
||
return pages
|
||
},
|
||
// 首页只显示前8个商品,每行2个
|
||
displayProducts() {
|
||
return this.primaryProducts
|
||
}
|
||
},
|
||
methods: {
|
||
// 检查登录状态
|
||
checkLogin() {
|
||
this. token = uni.getStorageSync('token')
|
||
if (!this. token) {
|
||
uni.redirectTo({
|
||
url: '/pages/login/login'
|
||
})
|
||
}
|
||
},
|
||
|
||
// 加载数据
|
||
async loadData() {
|
||
try {
|
||
// 加载首页数据
|
||
const res = await request.get('/back/user/home/data')
|
||
if (res.success) {
|
||
this.banners = res.data.banners || []
|
||
this.categories = res.data.categories || []
|
||
this.primaryProducts = res.data.primary_products || []
|
||
this.primaryProducts=this.primaryProducts.slice(0,12)
|
||
}
|
||
} catch (error) {
|
||
console.error('加载首页数据失败:', error)
|
||
// uni.showToast({
|
||
// title: '加载数据失败',
|
||
// icon: 'none'
|
||
// })
|
||
}
|
||
},
|
||
|
||
// 获取完整的图片URL
|
||
getFullImageUrl(url) {
|
||
return request.getImageUrl(url)
|
||
},
|
||
|
||
// 获取商品的第一张图片
|
||
getFirstImage(images) {
|
||
if (!images) return ''
|
||
// 如果是逗号分隔的字符串
|
||
if (typeof images === 'string') {
|
||
return images.split(',')[0].trim()
|
||
}
|
||
// 如果是数组
|
||
if (Array.isArray(images) && images.length > 0) {
|
||
return images[0]
|
||
}
|
||
return ''
|
||
},
|
||
|
||
// 导航到分类页面(商城页面)
|
||
navigateToCategory(categoryId) {
|
||
|
||
uni.setStorage({
|
||
data:categoryId,
|
||
key:"categoryId",
|
||
success() {
|
||
setTimeout(()=>{
|
||
uni.switchTab({
|
||
url: `/pages/mall/mall`
|
||
})
|
||
},500)
|
||
|
||
}
|
||
})
|
||
|
||
},
|
||
|
||
// 导航到商品详情
|
||
navigateToProduct(productId) {
|
||
uni.navigateTo({
|
||
url: `/pages/product/detail?id=${productId}&type=primary`
|
||
})
|
||
},
|
||
|
||
// 轮播图点击事件
|
||
onBannerClick(banner) {
|
||
if (banner.link_url) {
|
||
// 如果有链接,跳转到对应页面
|
||
if (banner.link_url.startsWith('http')) {
|
||
// 外部链接,打开浏览器
|
||
// #ifdef APP-PLUS
|
||
plus.runtime.openURL(banner.link_url)
|
||
// #endif
|
||
// #ifdef H5
|
||
window.open(banner.link_url, '_blank')
|
||
// #endif
|
||
} else {
|
||
// 内部链接,使用uni.navigateTo
|
||
uni.navigateTo({
|
||
url: banner.link_url
|
||
})
|
||
}
|
||
}
|
||
},
|
||
|
||
// 查看全部商品
|
||
async viewAllProducts() {
|
||
try {
|
||
// 加载首页数据
|
||
const res = await request.get('/back/user/home/data')
|
||
if (res.success) {
|
||
this.banners = res.data.banners || []
|
||
this.categories = res.data.categories || []
|
||
this.primaryProducts = res.data.primary_products || []
|
||
|
||
}
|
||
} catch (error) {
|
||
console.error('加载首页数据失败:', error)
|
||
// uni.showToast({
|
||
// title: '加载数据失败',
|
||
// icon: 'none'
|
||
// })
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.container {
|
||
background-color: #f5f5f5;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
/* 搜索框样式 */
|
||
.search-container {
|
||
background: linear-gradient(135deg, #FF4444 0%, #FF6666 100%);
|
||
padding: 20rpx;
|
||
}
|
||
|
||
.search-box {
|
||
background-color: #fff;
|
||
border-radius: 50rpx;
|
||
padding: 20rpx 30rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.search-box uni-icons {
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.search-input {
|
||
flex: 1;
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
}
|
||
|
||
/* 轮播图样式 */
|
||
.banner-container {
|
||
margin: 20rpx;
|
||
border-radius: 16rpx;
|
||
overflow: hidden;
|
||
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.banner-swiper {
|
||
height: 300rpx;
|
||
}
|
||
|
||
.banner-item {
|
||
position: relative;
|
||
height: 100%;
|
||
}
|
||
|
||
.banner-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.banner-content {
|
||
position: absolute;
|
||
right: 30rpx;
|
||
top: 30rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.banner-title {
|
||
display: block;
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
margin-bottom: 10rpx;
|
||
color: #fff;
|
||
text-shadow: 1px 1px 2px rgba(0,0,0,0.5);
|
||
}
|
||
|
||
.banner-description {
|
||
display: block;
|
||
font-size: 24rpx;
|
||
color: #fff;
|
||
text-shadow: 1px 1px 2px rgba(0,0,0,0.5);
|
||
}
|
||
|
||
/* 分类容器样式 */
|
||
.category-container {
|
||
margin: 20rpx;
|
||
background-color: #fff;
|
||
border-radius: 16rpx;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.category-swiper {
|
||
height: 400rpx;
|
||
|
||
}
|
||
|
||
/* 分类网格样式 */
|
||
.category-grid {
|
||
padding: 40rpx 20rpx;
|
||
}
|
||
|
||
.category-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-bottom: 40rpx;
|
||
}
|
||
|
||
.category-row:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.category-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
width: 140rpx;
|
||
}
|
||
|
||
.category-item uni-icons {
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.category-icon {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.category-text {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
}
|
||
|
||
/* 商品区域样式 */
|
||
.product-section {
|
||
margin: 20rpx;
|
||
background-color: #fff;
|
||
border-radius: 16rpx;
|
||
padding: 30rpx;
|
||
}
|
||
|
||
.section-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.view-all {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
/* 商品网格样式 */
|
||
.product-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.product-item {
|
||
background-color: #f8f8f8;
|
||
border-radius: 12rpx;
|
||
overflow: hidden;
|
||
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.product-image-container {
|
||
width: 100%;
|
||
height: 200rpx;
|
||
position: relative;
|
||
}
|
||
|
||
.product-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.default-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background-color: #f0f0f0;
|
||
}
|
||
|
||
.product-info {
|
||
padding: 20rpx;
|
||
}
|
||
|
||
.product-name {
|
||
display: block;
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 10rpx;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.product-description {
|
||
display: block;
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
margin-bottom: 15rpx;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.product-price {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.current-price {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #FF4444;
|
||
margin-right: 15rpx;
|
||
}
|
||
|
||
.original-price {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
text-decoration: line-through;
|
||
}
|
||
|
||
.product-stats {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.stats-text {
|
||
font-size: 22rpx;
|
||
color: #999;
|
||
}
|
||
</style> |