2025-09-03 11:12:02 +08:00

397 lines
12 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>
<view class="merchantList">
<view class="searchBox">
<view class="searchBox_left">
<image
src="https://wechat-img-file.oss-cn-beijing.aliyuncs.com/property-img-file/com_communitySearchIcon.png"
@click="search">
</image>
<u--input v-model="searchQuery" @focus="iptFocus" @blur="iptBlur" @confirm="search" placeholder="搜索商品"
border="surround" clearable></u--input>
</view>
<view class="searchBox_right">
<view class="cars" @click="goCar">
<u-badge numberType="limit" type="error" max="99" :value="value"></u-badge>
<image src="https://wechat-img-file.oss-cn-beijing.aliyuncs.com/property-img-file/shop_car.png"
mode="widthFix"></image>
</view>
</view>
</view>
<!-- 搜索联系 -->
<!-- <view class="searchMore" v-if="!isSearched && searchHistory.length > 0">
<view class="searchMoreItem">猪肉肠</view>
<view class="searchMoreItem">猪肉肠</view>
<view class="searchMoreItem">猪肉肠</view>
</view> -->
<!-- 搜索历史 -->
<view class="his" v-if="!isSearched && searchHistory.length > 0">
<view class="hisTop">
<view class="hisTit">搜索历史</view>
<u-icon name="trash" color="#999999" size="40" class="history-trash" @click="deleteHistory"></u-icon>
</view>
<view class="HisList">
<view v-for="(item, index) in searchHistory" :key="index" class="HisItem" @click="selectHistory(item)">
{{ item }}</view>
</view>
</view>
<!-- 未搜索到 -->
<view class="empty" v-if="isSearched && searchGoodsLisat.length == 0">
<image src="https://wechat-img-file.oss-cn-beijing.aliyuncs.com/property-img-file/com_noSearch.png"></image>
对不起没有找到您想要的商品
</view>
<view class="searchList" v-if="isSearched && searchGoodsLisat.length > 0">
<!-- <view class="searchSubTit">
<view class="searchSubItem">综合</view>
<view class="searchSubItem">
价格
<view class="iconBox">
</view>
</view>
</view> -->
<view v-for="(item, index) in searchGoodsLisat" :key="index">
<view class="CateInfo_Item_Box">
<view class="CateInfo_Item_left" @click="goods(item)">
<view class="tag tag-img" v-if="
!item.commodity_goods_info_list[1] &&
item.commodity_goods_info_list[0].is_same_day
">当日达</view>
<image :src="handleImageUrl(item.commodity_pic)" mode="aspectFill"></image>
</view>
<view class="CateInfo_Item_right" :class="GGshow ? 'noneBor' : ''">
<view class="CateInfo_Item_right_Tit" @click="goods(item)">
<view class="tag tag-text" v-if="
!item.commodity_goods_info_list[1] &&
item.commodity_goods_info_list[0].is_same_day
">当日达</view>
{{ item.commodity_name }}
</view>
<view class="CateInfo_Item_right_subtit" @click="goods(item)">
{{ item.commodity_intro }}
</view>
<view class="CateInfo_Item_Money">
<view class="CateInfo_Item_Money_left">
{{ getPriceRange(item.commodity_goods_info_list) }}
</view>
<view class="CateInfo_Item_Money_right" v-if="!(item.commodity_goods_info_list.length > 1)">
<u-number-box :min="0" v-model="item.commodity_goods_info_list[0].quantity"
@change="(value) => handleQuantityChange(value, item)">
<view slot="minus" class="minus">
<u-icon name="minus" size="20"></u-icon>
</view>
<text slot="input" style="width: 50px; text-align: center" class="input">{{
item.commodity_goods_info_list[0].quantity
? item.commodity_goods_info_list[0].quantity
: 0
}}</text>
<view slot="plus" class="plus">
<u-icon name="plus" color="#FFFFFF" size="20"></u-icon>
</view>
</u-number-box>
</view>
</view>
<view class="gg" @click="chooseGG(item)" v-if="
item.commodity_goods_info_list.length > 1 && !item.isShow
">
选择规格
<u-icon name="arrow-down" size="26rpx" color="#FF370B"></u-icon>
</view>
<view class="gg" @click="chooseGG(item)" v-if="
item.commodity_goods_info_list.length > 1 && item.isShow
">
收起
<u-icon name="arrow-up" size="26rpx" color="#FF370B"></u-icon>
</view>
</view>
</view>
<view class="GGList" v-if="item.isShow">
<view class="GGItem" v-for="ite in item.commodity_goods_info_list" :key="ite.id"
@click="goods(item)">
<view class="GGItem_Image">
<view class="tag tag-img" v-if="ite.is_same_day">当日达</view>
<image :src="handleImageUrl(ite.commodity_pic)" mode="aspectFill"></image>
</view>
<view class="GGItem_Con">
<view class="GGItem_Con_Tit">
<view class="tag tag-text" v-if="ite.is_same_day">当日达</view>
{{ ite.goods_name }}
</view>
<view class="GGItem_Con_Msg">
<view class="GGItem_Con_Msg_left">
<span>¥</span>{{ ite.sales_price }}
</view>
<view class="GGItem_Con_Msg_right">
<u-number-box v-model="ite.quantity" :min="0"
@change="(value) => handleQuantityChange(value, ite)">
<view slot="minus" class="minus">
<u-icon name="minus" size="20"></u-icon>
</view>
<text slot="input" style="width: 50px; text-align: center" class="input">{{
ite.quantity ?
ite.quantity : 0 }}</text>
<view slot="plus" class="plus">
<u-icon name="plus" color="#FFFFFF" size="20"></u-icon>
</view>
</u-number-box>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
apiArr
} from '../../../api/shop';
import {
picUrl as basePicUrl,
menuButtonInfo,
request,
NavgateTo
} from '../../../utils';
export default {
data() {
return {
flag: false,
value: 0,
isSearch: false,
isSearched: false,
searchQuery: '',
searchHistory: [],
searchGoodsLisat: [],
goodsDetail: []
}
},
methods: {
goCar() {
NavgateTo('/packages/shop/shopCar/index')
},
getShopCar() {
request(apiArr.getCar, "POST", {}).then((res) => {
this.value = res.total;
});
},
// 获取购物车数据
getShopCarList() {
request(apiArr.getCar, "POST").then((res) => {
this.value = res.total;
// 合并当日达和普通商品数据
this.goodsDetail = [].concat(res.same_day_cart_list || [], res.normal_cart_list || [])
.flatMap(supplier => supplier.commodity_cart_and_goods_model || []);
});
},
search() {
if (this.searchQuery.trim()) {
// 保存搜索历史到storage
this.saveSearchHistory();
// 设置搜索状态为已搜索
this.isSearched = true;
// 隐藏搜索历史面板
this.isSearch = false;
const params = {
query: this.searchQuery,
user_id: uni.getStorageSync('userId')
}
request(apiArr.goodsSearch, "POST", params).then((res) => {
// 深拷贝接口数据,避免引用问题
const commodityList = JSON.parse(JSON.stringify(res.commodity_list));
commodityList.forEach((item) => {
// 初始化isShow为响应式属性
this.$set(item, 'isShow', false);
item.commodity_goods_info_list.forEach((param) => {
// 从购物车数据中查找对应商品的数量否则设为0
const goods = this.goodsDetail.find(g => g.goods_id === param.id);
this.$set(param, 'quantity', goods ? goods.count : 0);
});
});
this.searchGoodsLisat = commodityList;
});
}
},
ipt1(e) {
console.log(e);
},
iptFocus() {
this.isSearch = true;
this.loadSearchHistory();
},
iptBlur() {
if (this.searchQuery) {
this.search();
} else {
this.searchGoodsLisat = [];
this.isSearch = true
this.isSearched = false
}
},
// 保存搜索历史
saveSearchHistory() {
if (this.searchQuery && !this.searchHistory.includes(this.searchQuery)) {
// 添加到数组开头
this.searchHistory.unshift(this.searchQuery);
// 限制最多保存10条历史记录
if (this.searchHistory.length > 10) {
this.searchHistory.pop();
}
// 保存到storage
uni.setStorageSync('shopSearchHistory', this.searchHistory);
}
},
// 加载搜索历史
loadSearchHistory() {
const history = uni.getStorageSync('shopSearchHistory') || [];
this.searchHistory = history;
},
// 选择历史记录进行搜索
selectHistory(item) {
this.searchQuery = item;
this.search();
this.isSearch = false;
},
// 清除搜索历史
deleteHistory() {
uni.showModal({
title: '提示',
content: '确定清除所有搜索历史吗?',
success: (res) => {
if (res.confirm) {
this.searchHistory = [];
uni.removeStorageSync('shopSearchHistory');
uni.showToast({
title: '搜索历史已清除',
icon: 'none'
});
}
}
});
},
// 商品详情页
goods(e) {
NavgateTo(`../goods/index?item=${JSON.stringify(e)}`);
},
// 选择商品规格
chooseGG(targetItems) {
// 遍历商品列表找到目标对象
const itemIndex = this.searchGoodsLisat.findIndex(item => item.id === targetItems.id);
if (itemIndex > -1) {
// 直接修改数据源中的对象,确保响应式
const currentItem = this.searchGoodsLisat[itemIndex];
this.$set(currentItem, 'isShow', !currentItem.isShow);
}
},
// 处理商品数量变化
handleQuantityChange(val, item) {
// 先在前端直接更新数量,确保页面显示及时变化
// 注意这里的val可能是直接的数值也可能是包含value属性的对象
const quantity = typeof val === 'object' && val !== null && 'value' in val ? val.value : val;
// 对于有规格的主商品绑定到items.commodity_goods_info_list[0].quantity
if (item.commodity_goods_info_list && item.commodity_goods_info_list.length) {
this.goodsId = item.commodity_goods_info_list[0].id;
// 使用$set确保响应式更新
this.$set(item.commodity_goods_info_list[0], 'quantity', quantity);
}
// 对于规格列表中的商品绑定到ite.quantity
else {
this.goodsId = item.id;
// 使用$set确保响应式更新
this.$set(item, 'quantity', quantity);
}
const params = {
user_id: uni.getStorageSync('userId'),
goods_id_and_count: [
{
goods_id: this.goodsId,
count: quantity,
},
],
};
request(apiArr.updateCar, 'POST', params).then((res) => {
console.log(res);
// 更新购物车数据
this.getShopCarList();
// 延迟时间确保goodsDetail已经更新
setTimeout(() => {
// 重新同步商品列表中的数量
this.syncGoodsQuantities();
}, 100);
uni.showToast({
title: '操作成功!',
success() { },
});
});
},
// 同步商品列表中的数量与购物车数据
syncGoodsQuantities() {
// 遍历所有商品,同步数量
this.searchGoodsLisat.forEach((item) => {
item.commodity_goods_info_list.forEach((param) => {
const goods = this.goodsDetail.find(g => g.goods_id === param.id);
if (goods) {
this.$set(param, 'quantity', goods.count);
}
});
});
},
// 获取价格范围
getPriceRange(goodsList) {
if (!goodsList || goodsList.length === 0) return '¥0';
const prices = goodsList.map(item => Number(item.sales_price));
const minPrice = Math.min(...prices);
const maxPrice = Math.max(...prices);
return minPrice === maxPrice ? `${minPrice}` : `${minPrice} ~ ¥${maxPrice}`;
},
// 处理图片路径
handleImageUrl(imagePath) {
return basePicUrl + imagePath;
}
},
watch: {
searchQuery: {
handler(newVal, oldVal) {
if (!newVal) {
this.searchGoodsLisat = [];
this.isSearch = true
this.isSearched = false
}
},
deep: true
}
},
onLoad(options) {
this.loadSearchHistory();
this.isSearch = false;
this.isSearched = false;
},
onShow() {
this.getShopCarList();
},
onReachBottom() {
if (this.flag) {
}
},
}
</script>
<style>
@import url("./index.css");
</style>