【类 型】:feat

【原  因】:搜索功能相关 页面组件
【过  程】:1.serarch.vue组页面 2把购物车按钮提取出来作为单独组件3.前端搜索 在前端做数据过滤进行 搜索结果的输出
【影  响】:

# 类型 包含:
# feat:新功能(feature)
# fix:修补bug
# docs:文档(documentation)
# style: 格式(不影响代码运行的变动)
# refactor:重构(即不是新增功能,也不是修改bug的代码变动)
# test:增加测试
# chore:构建过程或辅助工具的变动
This commit is contained in:
air 2025-01-21 18:27:59 +08:00
parent c6ac6c9292
commit 5925265e69
4 changed files with 178 additions and 70 deletions

View File

@ -75,6 +75,11 @@
transition: all 0.2s ease;
}
.topbar {
background-color: $uni-color-error;
height: 176rpx;
}
//
.extra-space {
height: 156rpx;

View File

@ -28,16 +28,68 @@
</template>
<script>
import {
formatPrice,
totalPrice
} from '@/utils/index.js'
export default {
name: "cartBut",
data() {
return {
};
}
},
methods: {
//
totalPrice,
//""
handleSeled() {
const regex = /^(\+?\d{1,4}[\s-]?)?\d{3}\*{4}\d{4}$/
if (regex.test(this.$store.state.userInfo.tel)) { //
if (Number(this.minimumOrderDifference) <= 0) { //
uni.navigateTo({ //
url: '/pages/shop/confirm'
})
} else {
uni.showToast({
title: '未达到起送价',
icon: 'error'
})
}
} else { //
uni.navigateTo({ //
url: '/pages/main/getTel'
})
}
}
},
computed: {
//
total() {
return this.totalPrice(this.$store.state.cartList)
},
//
minimumOrderDifference() {
return Number(this.shopCon.price_min) - Number(this.total)
},
//
shopCon() {
return this.$store.state.shopCon
},
},
filters: {
formatPrice //
}
}
</script>
<style>
<style lang="scss" scoped>
.cartBox {
z-index: 10071;
width: calc(100vw - 48rpx);
height: 156rpx;
background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.7) 70%, rgba(255, 255, 255, 1) 100%);
position: absolute;
bottom: 0rpx;
}
</style>

View File

@ -1,10 +1,16 @@
<template>
<view class="vh100 flex column">
<!-- topbar -->
<u-navbar title="开始点餐" bgColor="#d43030" :titleStyle="{ color: '#FFF'}" :autoBack="true" placeholder>
<u-navbar bgColor="#d43030" :titleStyle="{ color: '#FFF'}" :autoBack="true" placeholder>
<view class="u-nav-slot" slot="left">
<u-icon name="arrow-left" color="#fff" size="19"></u-icon>
</view>
<view class="u-nav-slot ofh" slot="center" @click="handlerGoSearch">
<view class="searchBut flex mac fz28 fcb p-l-24 rad16">
<u-icon name="search" color="#e5e5e5" size="28"></u-icon>
搜一搜你想吃的餐品
</view>
</view>
</u-navbar>
<!-- 地址框 -->
<view class="flex column p-24 borderB bg-w">
@ -61,33 +67,7 @@
</scroll-view>
</view>
<!-- 购物车按钮 -->
<view class="p-l-24 p-r-24 cartBox">
<view v-if="total === 0" class="rad16 bg-g flex ofh" style="height: 108rpx;">
<view class="bg-b" style="width: 152rpx;"></view>
<view class="flex1 flex mac p-l-24">
<u--image src="/static/icons/cafe-48.svg" width="96rpx" height="96rpx" />
<view class="m-l-12 fz36 fb">未选购餐品</view>
</view>
</view>
<view v-else class="bg-m rad16 flex" style="height: 108rpx;">
<view class="flex md p-b-12">
<u--image src="/static/icons/planeBox-100.svg" width="136rpx" height="136rpx"
@click="$store.commit('setCartShow',!$store.state.cartShow)" />
</view>
<view class="fci fz36 flex1 flex msb">
<view class="flex1 p-l-12 flex column mc"
@click="$store.commit('setCartShow',!$store.state.cartShow)">
<view class="fz36 fb">¥{{total | formatPrice}}</view>
<view class="fz24" v-if="minimumOrderDifference>0">还差¥{{minimumOrderDifference | formatPrice}}起送
</view>
</view>
<view class="flex column mac mc" style="width: 180rpx;" @click="handleSeled">
<view class="fz36">选好了</view>
<view class="fz24">Order</view>
</view>
</view>
</view>
</view>
<cartBut></cartBut>
<!-- 购物车折叠层 -->
<cartFold></cartFold>
</view>
@ -95,9 +75,7 @@
<script>
import {
formatTime,
formatPrice,
totalPrice
formatTime
} from '@/utils/index.js'
export default {
@ -136,10 +114,6 @@
shopCon() {
return this.$store.state.shopCon
},
//
minimumOrderDifference() {
return Number(this.shopCon.price_min) - Number(this.total)
},
//
menuList() {
return this.$store.state.menuList
@ -148,14 +122,14 @@
spuList() {
return this.$store.state.spuList
},
//
total() {
return this.totalPrice(this.$store.state.cartList)
}
},
methods: {
//
totalPrice,
//
handlerGoSearch() {
uni.navigateTo({
url: '/pages/shop/search'
})
},
//
async swichMenu(index) {
clearTimeout(this.scrollingTiemout) //timeout
@ -267,31 +241,20 @@
}
}, 10)
},
//""
handleSeled() {
const regex = /^(\+?\d{1,4}[\s-]?)?\d{3}\*{4}\d{4}$/
if (regex.test(this.$store.state.userInfo.tel)) { //
uni.navigateTo({ //
url: '/pages/shop/confirm'
})
} else { //
uni.navigateTo({ //
url: '/pages/main/getTel'
})
}
}
},
filters: {
formatTime, //
formatPrice //
}
}
</script>
<style lang="scss" scoped>
.topbar {
background-color: $uni-color-error;
height: 176rpx;
.searchBut {
margin-right: 100rpx;
color: #e5e5e5;
width: 360rpx;
height: 64rpx;
background-color: rgba(0, 0, 0, 0.15);
}
.backBut {
@ -337,13 +300,4 @@
.menuItemH {
background-color: $uni-color-error;
}
.cartBox {
z-index: 10071;
width: calc(100vw - 48rpx);
height: 156rpx;
background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.7) 70%, rgba(255, 255, 255, 1) 100%);
position: absolute;
bottom: 0rpx;
}
</style>

97
pages/shop/search.vue Normal file
View File

@ -0,0 +1,97 @@
<template>
<view class="vh100 flex column">
<!-- topbar -->
<u-navbar title="搜索商品" bgColor="#d43030" :titleStyle="{ color: '#FFF'}" :autoBack="true" placeholder>
<view class="u-nav-slot" slot="left">
<u-icon name="arrow-left" color="#fff" size="19"></u-icon>
</view>
</u-navbar>
<!-- 搜索框 -->
<view class="search-container flex mac m-l-24 m-r-24">
<input class="borderno rad16 m-r-12 bg-w fz28 p-12 flex1" v-model="searchQuery" placeholder="请输入商品名称"
@input="handleSearch" />
<u-icon name="search" color="#d43030" size="32" @click="handleSearch"></u-icon>
</view>
<!-- 搜索结果展示 -->
<view class="m-l-24 m-r-24 flex1 ofa">
<view v-if="filteredSpuList.length > 0">
<listItem v-for="spuItem in filteredSpuList" :key="spuItem.id" :spu="spuItem" />
</view>
<template v-else>
<u-divider v-if="searchQuery" text="没有找到相关商品" :hairline="true"></u-divider>
</template>
<!-- 底部空白占位 -->
<view class="extra-space2"></view>
</view>
<!-- 购物车按钮 -->
<cartBut></cartBut>
<!-- 购物车折叠层 -->
<cartFold></cartFold>
</view>
</template>
<script>
export default {
data() {
return {
searchQuery: '', //
filteredSpuList: [], // spu
}
},
computed: {
// spuList Vuex
spuList() {
return this.$store.state.spuList
}
},
watch: {
// spuList
spuList(newSpuList) {
this.filteredSpuList = this.filterSpuList(this.searchQuery, newSpuList)
},
// searchQuery
searchQuery(newQuery) {
this.filteredSpuList = this.filterSpuList(newQuery, this.spuList)
}
},
methods: {
//
handleSearch() {
if (this.searchQuery.trim() === '') {
this.filteredSpuList = [] //
} else {
this.filteredSpuList = this.filterSpuList(this.searchQuery, this.spuList) //
}
},
// spuList
filterSpuList(query, spuList) {
if (!query.trim()) return [] //
const lowerQuery = query.toLowerCase()
return spuList.filter(spuItem => {
// name
const nameMatch = spuItem.name.toLowerCase().includes(lowerQuery)
// pro_tag
const tagMatch = spuItem.pro_tag.some(tag => tag.toLowerCase().includes(lowerQuery))
// bind_sku name
const skuMatch = spuItem.bind_sku.some(sku => sku.tit.toLowerCase().includes(lowerQuery))
// namepro_tag bind_sku spu
return nameMatch || tagMatch || skuMatch
})
}
}
}
</script>
<style scoped>
.search-container {
height: 100rpx;
}
</style>