375 lines
13 KiB
Vue
375 lines
13 KiB
Vue
<template>
|
||
<view class="main">
|
||
<!-- 顶部搜索栏 -->
|
||
<view class="header" :style="{ paddingTop: menu.top + 'px' }">
|
||
<view class="headerTop" :style="{ height: menu.height + 'px' }">
|
||
<view class="backArrowBox" @click="handleBackHome">
|
||
<image class="backArrow" src="/static/images/home/backArrowblack.svg" />
|
||
</view>
|
||
<view class="pageName">自有水商城</view>
|
||
<view class="backArrowBox" style="visibility: hidden;"></view>
|
||
</view>
|
||
<view class="searchContainer">
|
||
<view class="searchBox">
|
||
<image class="searchIcon" src="/static/images/home/searchIcon.svg" />
|
||
<input class="searchInput" placeholder="搜索您需要的商品..." v-model="searchKey" @input="handleSearch"
|
||
confirm-type="search" />
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 商品列表 -->
|
||
<scroll-view class="pageContent" scroll-y @scrolltolower="handleLoadMore">
|
||
<view class="productGrid">
|
||
<view class="productItem" v-for="(item, index) in displayList" :key="index"
|
||
@click="handleGoDetail(item)">
|
||
<view class="imageWrapper">
|
||
<image class="productImg" :src="item.IMAGE_PATH || '/static/images/home/defultImg.png'"
|
||
mode="aspectFit" />
|
||
</view>
|
||
<view class="productInfo">
|
||
<view class="productTitle">{{ item.COMMODITY_NAME }}</view>
|
||
<view class="productBottom">
|
||
<view class="priceBox">
|
||
<view class="priceLeft">
|
||
<text class="unit">¥</text>
|
||
<text class="price">{{ item.COMMODITY_MEMBERPRICE }}</text>
|
||
</view>
|
||
<text class="commodityUnit">/ {{ item.COMMODITY_UNIT || "" }}</text>
|
||
</view>
|
||
<view class="actionBox">
|
||
<view class="addBtnWrapper">
|
||
<image class="addIcon" src="https://eshangtech.com/caiyunyiImg/home/newAddIcon.png"
|
||
@click.stop="addToCart(item)" />
|
||
<!-- 数量角标移至此处 -->
|
||
<view class="iconBadge" v-if="getCartCount(item) > 0">{{ getCartCount(item) }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="noMore" v-if="isOver && displayList.length > 0 && !searchKey">我是有底线的</view>
|
||
<view class="noData" v-if="displayList.length === 0">暂无相关商品</view>
|
||
<view style="height: 120rpx;"></view>
|
||
</scroll-view>
|
||
|
||
<!-- 底部 Tabbar -->
|
||
<own-water-tabbar :page="'/pages/ownWater/index'" :shopCarLength="totalCartCount" />
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import ownWaterTabbar from "@/components/ownWaterTabbar.vue";
|
||
|
||
export default {
|
||
components: {
|
||
ownWaterTabbar
|
||
},
|
||
data() {
|
||
return {
|
||
menu: {},
|
||
allProducts: [],
|
||
displayList: [],
|
||
searchKey: "",
|
||
pageIndex: 1,
|
||
pageSize: 20,
|
||
isOver: false,
|
||
waterCart: [],
|
||
totalCartCount: 0
|
||
};
|
||
},
|
||
onLoad() {
|
||
this.menu = uni.getMenuButtonBoundingClientRect();
|
||
this.handleGetProducts();
|
||
this.syncCartData();
|
||
},
|
||
onShow() {
|
||
this.syncCartData();
|
||
},
|
||
methods: {
|
||
handleBackHome() {
|
||
uni.switchTab({
|
||
url: "/pages/index/index"
|
||
});
|
||
},
|
||
handleGoDetail(item) {
|
||
uni.navigateTo({
|
||
url: `/pages/ownWater/waterShopDetail?data=${encodeURIComponent(JSON.stringify(item))}`
|
||
});
|
||
},
|
||
handleSearch() {
|
||
if (!this.searchKey) {
|
||
this.displayList = this.allProducts;
|
||
return;
|
||
}
|
||
this.displayList = this.allProducts.filter(item =>
|
||
item.COMMODITY_NAME.toLowerCase().includes(this.searchKey.toLowerCase())
|
||
);
|
||
},
|
||
async handleGetProducts() {
|
||
if (this.isOver) return;
|
||
uni.showLoading({ title: "加载中..." });
|
||
|
||
|
||
const res = await this.$api.$samemberGet('/EShangApiMain/WeChatMall/GetTypeAndGoodsList', {
|
||
WareHouseId: 289
|
||
})
|
||
|
||
if (res && res.Result_Code === 100 && res.Result_Data) {
|
||
const list = this.extractProducts(res.Result_Data.List || []);
|
||
// 该接口似乎一次性返回所有数据(PageSize: 0),设置 isOver 为 true
|
||
this.isOver = true;
|
||
this.allProducts = list;
|
||
this.handleSearch();
|
||
} else {
|
||
uni.showToast({ title: (res && res.Result_Desc) || "加载失败", icon: "none" });
|
||
}
|
||
|
||
uni.hideLoading();
|
||
},
|
||
extractProducts(apiList) {
|
||
let res = [];
|
||
if (apiList && apiList.length > 0) {
|
||
apiList.forEach(category => {
|
||
if (category.CommodityList && category.CommodityList.length > 0) {
|
||
category.CommodityList.forEach(item => {
|
||
// 字段映射:适配原有组件及购物车逻辑
|
||
// COSTTAXPRICE -> COMMODITY_MEMBERPRICE
|
||
// SELLERCOMMODITY_ID -> COMMODITY_ID
|
||
item.COMMODITY_MEMBERPRICE = item.COSTTAXPRICE;
|
||
item.COMMODITY_ID = item.SELLERCOMMODITY_ID;
|
||
res.push(item);
|
||
});
|
||
}
|
||
});
|
||
}
|
||
return res;
|
||
},
|
||
handleLoadMore() {
|
||
if (!this.searchKey) {
|
||
this.handleGetProducts();
|
||
}
|
||
},
|
||
syncCartData() {
|
||
this.waterCart = uni.getStorageSync("waterShopCar") || [];
|
||
this.totalCartCount = this.waterCart.reduce((acc, item) => acc + (item.count || 0), 0);
|
||
},
|
||
getCartCount(item) {
|
||
const found = this.waterCart.find(cartItem => cartItem.COMMODITY_ID === item.COMMODITY_ID);
|
||
return found ? found.count : 0;
|
||
},
|
||
addToCart(item) {
|
||
let cart = uni.getStorageSync("waterShopCar") || [];
|
||
const index = cart.findIndex(cartItem => cartItem.COMMODITY_ID === item.COMMODITY_ID);
|
||
|
||
if (index > -1) {
|
||
cart[index].count++;
|
||
} else {
|
||
cart.push({
|
||
...item,
|
||
count: 1,
|
||
select: true // 默认选中
|
||
});
|
||
}
|
||
|
||
uni.setStorageSync("waterShopCar", cart);
|
||
this.syncCartData();
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.main {
|
||
background: #f5f5f5;
|
||
min-height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
.header {
|
||
background: #fff;
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 100;
|
||
|
||
.headerTop {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 30rpx;
|
||
|
||
.backArrowBox {
|
||
width: 60rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.backArrow {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
}
|
||
|
||
.pageName {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
|
||
.searchContainer {
|
||
padding: 20rpx 30rpx;
|
||
|
||
.searchBox {
|
||
height: 72rpx;
|
||
background: #f0f0f0;
|
||
border-radius: 36rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 0 30rpx;
|
||
|
||
.searchIcon {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
margin-right: 16rpx;
|
||
}
|
||
|
||
.searchInput {
|
||
flex: 1;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.pageContent {
|
||
flex: 1;
|
||
padding: 20rpx;
|
||
box-sizing: border-box;
|
||
|
||
.productGrid {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: space-between;
|
||
|
||
.productItem {
|
||
width: 345rpx;
|
||
background: #fff;
|
||
border-radius: 20rpx;
|
||
margin-bottom: 20rpx;
|
||
overflow: hidden;
|
||
position: relative;
|
||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
|
||
|
||
.imageWrapper {
|
||
position: relative;
|
||
width: 100%;
|
||
height: 320rpx;
|
||
background: #fff;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 20rpx;
|
||
box-sizing: border-box;
|
||
|
||
.productImg {
|
||
width: 100%;
|
||
height: 100%;
|
||
border-radius: 12rpx;
|
||
}
|
||
}
|
||
|
||
.productInfo {
|
||
padding: 20rpx;
|
||
|
||
.productTitle {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
height: 76rpx;
|
||
overflow: hidden;
|
||
display: -webkit-box;
|
||
line-clamp: 2;
|
||
-webkit-line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
margin-bottom: 16rpx;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.productBottom {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
|
||
.priceBox {
|
||
display: flex;
|
||
align-items: baseline;
|
||
color: #ff4d4f;
|
||
|
||
.priceLeft {
|
||
display: flex;
|
||
align-items: baseline;
|
||
margin-right: 8rpx;
|
||
|
||
.unit {
|
||
font-size: 20rpx;
|
||
}
|
||
|
||
.price {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
|
||
.commodityUnit {
|
||
font-size: 20rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
.actionBox {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.addBtnWrapper {
|
||
position: relative;
|
||
width: 44rpx;
|
||
height: 44rpx;
|
||
|
||
.addIcon {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.iconBadge {
|
||
position: absolute;
|
||
top: -12rpx;
|
||
right: -12rpx;
|
||
background: #ff4d4f;
|
||
color: #fff;
|
||
font-size: 16rpx;
|
||
padding: 2rpx 8rpx;
|
||
border-radius: 20rpx;
|
||
min-width: 20rpx;
|
||
text-align: center;
|
||
border: 2rpx solid #fff;
|
||
z-index: 10;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.noMore,
|
||
.noData {
|
||
text-align: center;
|
||
padding: 40rpx 0;
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
}
|
||
</style>
|