youdas/pages/mall/mall.vue
2025-06-24 00:34:39 +08:00

393 lines
7.5 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>
<z-paging-swiper>
<template #top>
<view class="" style="width: 100%; height: 225.19rpx; background-color: white; position: relative;">
<view class="title">
商城
</view>
</view>
</template>
<z-paging ref="paging" show-refresher-update-time loading-more-no-more-text="我也是有底线的" v-model="dataList"
@query="queryList" :fixed="false" :show-loading-more-when-reload="true">
<!-- 搜索 -->
<text-search v-model="searchKeyword" placeholder="搜索商品" @search="handleSearch" @clear="clearSearch" />
<!-- 顶部三个商品 -->
<swiper v-if="!isSearch && topDataList.length > 0" :display-multiple-items="3" class="top" :duration="500">
<swiper-item v-for="(item, i) in topDataList" :key="i" @click="goToDetail(item)">
<view class="item">
<view class="img">
<image v-if="item.image" :src="item.image" mode="aspectFill" class="product-image">
</image>
</view>
<view class="item-info">
<view class="item-name">
{{ item.title }}
</view>
<view class="item-bottom">
<view class="item-price">
<text class="price-symbol-small">¥</text>
<text class="price-value-small">{{ item.price }}</text>
</view>
<view class="item-count">
<text class="count-text-small">{{ item.sales }}/{{ item.stock }}</text>
<image src="/static/ic_box.png" class="box-icon-small" mode="aspectFit"></image>
</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
<view class="view-list">
<view class="product-item" v-for="(item, i) in dataList" :key="i" @click="goToDetail(item)">
<view class="product-image-container">
<image v-if="item.image" :src="item.image" mode="aspectFill" class="product-image">
</image>
</view>
<view class="product-name">
{{ item.title }}
</view>
<view class="product-count">
<text class="count-text">{{ item.sales }}/{{ item.stock }}</text>
<image src="/static/ic_box.png" class="box-icon" mode="aspectFit"></image>
</view>
<view class="product-price">
<text class="price-symbol">¥</text>
<text class="price-value">{{ item.price }}</text>
</view>
<view class="buy-button" @click.stop="buyProduct(item)">
<text class="buy-text">购买</text>
</view>
</view>
</view>
<template #empty>
<no-data />
</template>
<template #loading>
<loading-data />
</template>
</z-paging>
</z-paging-swiper>
</template>
<script setup>
import { ref } from 'vue';
const paging = ref(null);
import { getProductList, getBannerList } from '@/common/server/product';
import TextSearch from '@/components/youdas-container/text-search.vue';
// 响应式数据
const topDataList = ref([
]);
let isSearch = ref(false);
const dataList = ref([]);
const searchKeyword = ref(''); // 搜索关键词
// 跳转到商品详情页
const goToDetail = (item) => {
uni.navigateTo({
url: `/pages/mall/product-detail?id=${item.id}`
});
};
// 购买商品
const buyProduct = (item, event) => {
// 阻止事件冒泡
event.stopPropagation();
// 检查库存
if (item.stock <= 0) {
uni.showToast({
title: '商品已售罄',
icon: 'none'
});
return;
}
// 添加到购物车或直接购买的逻辑
uni.showToast({
title: '已添加到购物车',
icon: 'success'
});
};
// 处理搜索
const handleSearch = () => {
if (searchKeyword.value == '') {
isSearch.value = false;
} else {
isSearch.value = true;
}
paging.value.reload();
};
// 清空搜索
const clearSearch = () => {
searchKeyword.value = '';
isSearch.value = false;
paging.value.reload();
};
const queryList = (pageNo, pageSize) => {
getProductList(pageNo, pageSize, searchKeyword.value).then(res => {
dataList.value.concat(res || []);
paging.value.complete(res || false);
});
};
onLoad(async () => {
const bannerList = await getBannerList();
topDataList.value = bannerList;
});
</script>
<style lang="scss">
.content {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background-color: #F7F7F7;
}
.title {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 32.44rpx;
font-weight: 600;
position: absolute;
bottom: 30rpx;
}
.top {
width: 688.94rpx;
height: 325.38rpx;
margin: 34rpx auto;
display: flex;
flex-direction: row;
justify-content: space-between;
.item {
width: 216.31rpx;
height: 100%;
background-color: #FFFFFF;
border-radius: 15.27rpx;
display: flex;
flex-direction: column;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
transition: transform 0.3s;
&:active {
transform: scale(0.98);
}
}
.img {
width: 100%;
height: 216.31rpx;
background-color: #F2F2F2;
border-radius: 15.27rpx 15.27rpx 0rpx 0rpx;
overflow: hidden;
.product-image {
width: 100%;
height: 100%;
}
}
.item-info {
width: 100%;
height: 109.07rpx;
position: relative;
padding: 8rpx;
box-sizing: border-box;
}
.item-name {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 19.08rpx;
color: #333333;
text-align: center;
margin-top: 6rpx;
}
.item-bottom {
position: absolute;
width: 100%;
bottom: 12rpx;
left: 0;
padding: 0 13rpx;
box-sizing: border-box;
display: flex;
justify-content: space-between;
}
.item-price {
display: flex;
flex-direction: row;
align-items: center;
}
.price-symbol-small {
font-size: 15.27rpx;
margin-top: 6rpx;
color: #FF6A6A;
}
.price-value-small {
font-size: 22.9rpx;
font-weight: bold;
color: #FF6A6A;
}
.item-count {
display: flex;
flex-direction: row;
align-items: center;
}
.count-text-small {
font-size: 15.27rpx;
color: #6C6C6C;
}
.box-icon-small {
width: 17.39rpx;
height: 17.39rpx;
margin-left: 7rpx;
}
}
.product-item {
width: 100%;
height: 261.45rpx;
background-color: #FFFFFF;
margin-bottom: 21rpx;
border-radius: 15.27rpx;
position: relative;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
transition: transform 0.3s;
&:active {
transform: scale(0.98);
}
}
.product-image-container {
width: 216.31rpx;
height: 216.31rpx;
background-color: #F2F2F2;
border-radius: 15.27rpx;
position: absolute;
left: 22rpx;
top: 22rpx;
overflow: hidden;
.product-image {
width: 100%;
height: 100%;
}
}
.product-name {
width: 350rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
position: absolute;
left: 269rpx;
top: 44rpx;
font-size: 26.72rpx;
font-weight: 600;
color: #333333;
}
.product-count {
position: absolute;
display: flex;
flex-direction: row;
left: 269rpx;
top: 95rpx;
align-items: center;
.count-text {
font-size: 15.27rpx;
color: #6C6C6C;
}
.box-icon {
width: 17.39rpx;
height: 17.39rpx;
margin-left: 7rpx;
}
}
.product-price {
position: absolute;
display: flex;
flex-direction: row;
left: 269rpx;
bottom: 44rpx;
align-items: center;
.price-symbol {
font-size: 19.08rpx;
margin-top: 15rpx;
color: #FF6A6A;
}
.price-value {
font-size: 34.35rpx;
font-weight: bold;
color: #FF6A6A;
}
}
.buy-button {
width: 89.22rpx;
height: 42rpx;
border-radius: 20.99rpx;
border: 1rpx solid #FF6A6A;
background-color: white;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
right: 38rpx;
bottom: 38rpx;
transition: all 0.3s;
&:active {
background-color: #FF6A6A;
.buy-text {
color: white;
}
}
.buy-text {
font-size: 19.08rpx;
color: #FF6A6A;
font-weight: 500;
}
}
</style>