编写易购模块的搜索页面

This commit is contained in:
赵毅 2025-09-03 11:12:02 +08:00
parent 47f1eaaa09
commit dc5e328b3c
3 changed files with 555 additions and 192 deletions

View File

@ -18,4 +18,6 @@ export const apiArr = {
getComment: '/api/v2/wechat/commodity/review/list', // 获取评论 getComment: '/api/v2/wechat/commodity/review/list', // 获取评论
mergePreorder: '/api/v2/wechat/commodity/order/preorder', // 商品订单合并预下单 mergePreorder: '/api/v2/wechat/commodity/order/preorder', // 商品订单合并预下单
goodsSearch: '/api/v2/wechat/commodity/search', // 商品搜索
} }

View File

@ -69,6 +69,12 @@ image {
margin-top: 48rpx; margin-top: 48rpx;
} }
.hisTop{
display: flex;
align-items: center;
justify-content: space-between;
}
.hisTit { .hisTit {
font-size: 33rpx; font-size: 33rpx;
color: #222222; color: #222222;
@ -170,8 +176,8 @@ image {
.searchItem_right { .searchItem_right {
flex: 1; flex: 1;
} }
.tag { .tag {
background-color: #ff7d00; background-color: #ff7d00;
color: white; color: white;
@ -182,24 +188,29 @@ image {
.tag-img { .tag-img {
position: absolute; position: absolute;
/* top: 1; */ top: 0;
bottom: 1; left: 0;
left: 10;
z-index: 1; z-index: 1;
} }
.tag-name { .tag-text {
background-color: #ff7d00; display: inline-block;
color: white; vertical-align: middle;
font-size: 22rpx; margin-right: 20rpx;
padding: 5rpx 10rpx; }
border-radius: 20rpx 0 20rpx 20rpx;
.tag-name {
background-color: #ff7d00;
color: white;
font-size: 22rpx;
padding: 5rpx 10rpx;
border-radius: 20rpx 0 20rpx 20rpx;
} }
.searchItem_right_tit { .searchItem_right_tit {
font-size: 30rpx; font-size: 30rpx;
color: #000000; color: #000000;
font-weight: 600; font-weight: 600;
display: flex; display: flex;
} }
@ -209,6 +220,171 @@ image {
margin-top: 10rpx; margin-top: 10rpx;
} }
/* 商品信息样式 */
.CateInfo_Item_Box {
display: flex;
padding: 20rpx 40rpx;
border-bottom: 1rpx solid #EBEBEB;
position: relative;
}
.CateInfo_Item_left {
width: 140rpx;
min-width: 140rpx;
height: 140rpx;
border-radius: 20rpx 20rpx 20rpx 20rpx;
overflow: hidden;
margin-right: 15rpx;
position: relative;
}
.CateInfo_Item_left image {
width: 100%;
height: 100%;
}
.CateInfo_Item_right {
flex: 1;
}
.CateInfo_Item_right_Tit {
font-size: 30rpx;
color: #000000;
font-weight: bold;
margin-bottom: 10rpx;
}
.CateInfo_Item_right_subtit {
font-size: 26rpx;
color: #999999;
margin-top: 10rpx;
}
.CateInfo_Item_Money {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 27rpx;
}
.CateInfo_Item_Money_left {
font-size: 34rpx;
color: #FF370B;
}
.CateInfo_Item_Money_left span {
font-size: 28rpx;
}
.CateInfo_Item_Money_right .input {
padding: 0;
}
/* 数量选择器样式 */
.minus {
width: 22px;
height: 22px;
border-width: 1px;
border-color: #E6E6E6;
border-style: solid;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
}
.input {
padding: 0 10px;
}
.plus {
width: 22px;
height: 22px;
background-color: #FF0000;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
}
/* 规格选择样式 */
.gg {
width: 142rpx;
height: 40rpx;
background: #FFEBEB;
border-radius: 20rpx 20rpx 20rpx 20rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
color: #FF370B;
position: absolute;
right: 100rpx;
bottom: 20rpx;
}
.GGList {
width: 550rpx;
background: rgba(255, 239, 239, 0.5);
border-radius: 20rpx 20rpx 20rpx 20rpx;
padding: 25rpx 16rpx;
box-sizing: border-box;
margin-left: 26rpx;
position: relative;
left: 22%;
}
.noneBor {
border-bottom: none;
}
.GGItem {
display: flex;
align-items: center;
margin-bottom: 10rpx;
}
.GGItem_Image {
width: 120rpx;
height: 100rpx;
margin: 0 20rpx 20rpx 0;
position: relative;
}
.GGItem_Image image {
border-radius: 20rpx;
}
.GGItem_Con_Tit {
font-size: 28rpx;
color: #000000;
}
.GGItem_Con {
flex: 1;
}
.GGItem_Con_Msg_left {
display: flex;
font-size: 30rpx;
color: #FF370B;
}
.GGItem_Con_Msg_left span {
font-size: 24rpx;
}
.GGItem_Con_Msg {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
}
.GGItem_Con_Msg_right .input {
padding: 0;
}
.searchItem_right_Money { .searchItem_right_Money {
display: flex; display: flex;
align-items: center; align-items: center;
@ -250,24 +426,24 @@ image {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
/* 测试用 */ /* 测试用 */
.search-input { .search-input {
width: 100%; width: 100%;
padding: 10px; padding: 10px;
border-radius: 5px; border-radius: 5px;
/* border: 1px solid #ccc; */ /* border: 1px solid #ccc; */
} }
.search-results { .search-results {
margin-top: 20px; margin-top: 20px;
} }
.result-item { .result-item {
padding: 10px; padding: 10px;
/* border-bottom: 1px solid #ddd; */ /* border-bottom: 1px solid #ddd; */
} }
/* 测试用 */ /* 测试用 */

View File

@ -1,109 +1,152 @@
<template> <template>
<view class="merchantList"> <view class="merchantList">
<div class="searchBox"> <view class="searchBox">
<div class="searchBox_left"> <view class="searchBox_left">
<image src="https://wechat-img-file.oss-cn-beijing.aliyuncs.com/property-img-file/com_communitySearchIcon.png"></image> <image
<u--input @focus="iptFocus" @blur="iptBlur" placeholder="搜索商品" border="surround" clearable></u--input> src="https://wechat-img-file.oss-cn-beijing.aliyuncs.com/property-img-file/com_communitySearchIcon.png"
@click="search">
<!-- 测试用 --> </image>
<!-- <input type="text" v-model="searchQuery" placeholder="请输入搜索内容" @input="onSearch" @focus="showHistory = true" class="search-input" /> <u--input v-model="searchQuery" @focus="iptFocus" @blur="iptBlur" @confirm="search" placeholder="搜索商品"
<view v-if="results.length" class="search-results"> border="surround" clearable></u--input>
<view class="result-item"> </view>
{{item}} <view class="searchBox_right">
</view> <view class="cars" @click="goCar">
</view> -->
<!-- 测试用 -->
</div>
<div class="searchBox_right">
<div class="cars">
<u-badge numberType="limit" type="error" max="99" :value="value"></u-badge> <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> <image src="https://wechat-img-file.oss-cn-beijing.aliyuncs.com/property-img-file/shop_car.png"
</div> mode="widthFix"></image>
</div> </view>
</div> </view>
</view>
<!-- 搜索联系 --> <!-- 搜索联系 -->
<div class="searchMore" v-if="isSearch"> <!-- <view class="searchMore" v-if="!isSearched && searchHistory.length > 0">
<div class="searchMoreItem">猪肉肠</div> <view class="searchMoreItem">猪肉肠</view>
<div class="searchMoreItem">猪肉肠</div> <view class="searchMoreItem">猪肉肠</view>
<div class="searchMoreItem">猪肉肠</div> <view class="searchMoreItem">猪肉肠</view>
</div> </view> -->
<!-- 搜索历史 --> <!-- 搜索历史 -->
<div class="his" v-if="isSearch"> <view class="his" v-if="!isSearched && searchHistory.length > 0">
<div class="hisTit">搜索历史</div> <view class="hisTop">
<div class="HisList"> <view class="hisTit">搜索历史</view>
<div class="HisItem">羊肉</div> <u-icon name="trash" color="#999999" size="40" class="history-trash" @click="deleteHistory"></u-icon>
<div class="HisItem">火锅底料</div> </view>
<div class="HisItem">蒜蓉辣酱</div> <view class="HisList">
<div class="HisItem">蒜蓉辣酱</div> <view v-for="(item, index) in searchHistory" :key="index" class="HisItem" @click="selectHistory(item)">
<div class="HisItem">蒜蓉辣酱</div> {{ item }}</view>
<div class="HisItem">蒜蓉辣酱</div> </view>
</div> </view>
</div>
<!-- 测试用 -->
<!-- <view v-if="showHistory && searchHistory.length > 0" class="history-list">
<view
v-for="(item, index) in searchHistory"
:key="index"
class="history-item"
@click="selectHistory(item)"
>
{{ item }}
</view>
</view> -->
<!-- 测试用 -->
<!-- 未搜索到 --> <!-- 未搜索到 -->
<div class="empty" v-if="false"> <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> <image src="https://wechat-img-file.oss-cn-beijing.aliyuncs.com/property-img-file/com_noSearch.png"></image>
对不起没有找到您想要的商品 对不起没有找到您想要的商品
</div> </view>
<div class="searchList"> <view class="searchList" v-if="isSearched && searchGoodsLisat.length > 0">
<div class="searchSubTit"> <!-- <view class="searchSubTit">
<div class="searchSubItem">综合</div> <view class="searchSubItem">综合</view>
<div class="searchSubItem"> <view class="searchSubItem">
价格 价格
<div class="iconBox"> <view class="iconBox">
</div> </view>
</div> </view>
</div> </view> -->
<div class="searchItem"> <view v-for="(item, index) in searchGoodsLisat" :key="index">
<div class="searchItem_left"> <view class="CateInfo_Item_Box">
<view class="tag tag-img">当日达</view> <view class="CateInfo_Item_left" @click="goods(item)">
<image src="https://wechat-img-file.oss-cn-beijing.aliyuncs.com/property-img-file/com_act2Img.png" mode="widthFix"></image> <view class="tag tag-img" v-if="
</div> !item.commodity_goods_info_list[1] &&
<div class="searchItem_right"> item.commodity_goods_info_list[0].is_same_day
<div class="searchItem_right_tit"><div class="tag-name" v-if="">当日达</div><div>泰国金枕榴莲</div></div> ">当日达</view>
<div class="searchItem_right_subTit">商品介绍商品介绍</div> <image :src="handleImageUrl(item.commodity_pic)" mode="aspectFill"></image>
<div class="searchItem_right_Money"> </view>
<div class="Money_left"> <view class="CateInfo_Item_right" :class="GGshow ? 'noneBor' : ''">
<div class="money_unit"></div> <view class="CateInfo_Item_right_Tit" @click="goods(item)">
125.9 <view class="tag tag-text" v-if="
<div class="Money_dw">/</div> !item.commodity_goods_info_list[1] &&
</div> item.commodity_goods_info_list[0].is_same_day
<div class="Money_right"> ">当日达</view>
<u-number-box v-model="value"> {{ item.commodity_name }}
<view slot="minus" class="minus"> </view>
<u-icon name="minus" size="22" bold></u-icon> <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>
<text slot="input" style="width: 80rpx;text-align: center;" class="input">{{ value <view class="GGItem_Con_Msg_right">
}}</text> <u-number-box v-model="ite.quantity" :min="0"
<view slot="plus" class="plus"> @change="(value) => handleQuantityChange(value, ite)">
<u-icon name="plus" color="#FFFFFF" size="22" bold></u-icon> <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>
</u-number-box> </view>
</div> </view>
</div> </view>
</div> </view>
</div> </view>
</div> </view>
</view> </view>
</template> </template>
@ -111,9 +154,9 @@
<script> <script>
import { import {
apiArr apiArr
} from '../../../api/doorToDoor'; } from '../../../api/shop';
import { import {
picUrl, picUrl as basePicUrl,
menuButtonInfo, menuButtonInfo,
request, request,
NavgateTo NavgateTo
@ -122,82 +165,224 @@ export default {
data() { data() {
return { return {
flag: false, flag: false,
value: 3, value: 0,
isSearch: false, isSearch: false,
isSearched: false,
searchQuery: '',
// searchHistory: [],
// searchQuery: '', searchGoodsLisat: [],
// results: [], // goodsDetail: []
// showHistory: false, //
// searchHistory: [] //
//
} }
}, },
methods: { 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() { 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) { ipt1(e) {
console.log(e); console.log(e);
}, },
iptFocus() { iptFocus() {
this.isSearch = true this.isSearch = true;
this.loadSearchHistory();
}, },
iptBlur() { iptBlur() {
this.isSearch = false if (this.searchQuery) {
}, this.search();
} else {
this.searchGoodsLisat = [];
// this.isSearch = true
// this.isSearched = false
// onSearch() { }
// // searchQuery },
// const fakeData = ['', '', '', '', '']; //
// this.results = fakeData.filter(item => item.includes(this.searchQuery)); saveSearchHistory() {
// if(this.searchQuery) { if (this.searchQuery && !this.searchHistory.includes(this.searchQuery)) {
// this.showHistory = true; //
// } else { this.searchHistory.unshift(this.searchQuery);
// this.showHistory = false // 10
// } if (this.searchHistory.length > 10) {
// }, this.searchHistory.pop();
}
// // // storage
// selectHistory(item) { uni.setStorageSync('shopSearchHistory', this.searchHistory);
// this.searchQuery = item; }
// this.onSearch(); },
// this.showHistory = false; //
// }, loadSearchHistory() {
const history = uni.getStorageSync('shopSearchHistory') || [];
// // this.searchHistory = history;
// saveSearchHistory() { },
// if(this.searchQuery && !this.searchHistory.includes(this.searchQuery)) { //
// this.searchHistory.unshift(this.searchQuery); // selectHistory(item) {
// if(this.searchHistory.length > 5) { this.searchQuery = item;
// this.searchHistory.pop(); // this.search();
// } this.isSearch = false;
// } },
// } //
deleteHistory() {
// uni.showModal({
title: '提示',
content: '确定清除所有搜索历史吗?',
}, success: (res) => {
if (res.confirm) {
// this.searchHistory = [];
// watch: { uni.removeStorageSync('shopSearchHistory');
// // uni.showToast({
// searchQuery(newQuery) { title: '搜索历史已清除',
// if(newQuery !== '') { icon: 'none'
// this.saveSearchHistory(); });
// } }
// } }
// }, });
},
// //
goods(e) {
onLoad(options) { 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) {
//
// valvalue
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() { onReachBottom() {
if (this.flag) { if (this.flag) {