411 lines
14 KiB
Vue
411 lines
14 KiB
Vue
<template>
|
|
<page-meta :page-style="$theme.pageStyle">
|
|
<!-- #ifndef H5 -->
|
|
<navigation-bar
|
|
:front-color="$theme.navColor"
|
|
:background-color="$theme.navBgColor"
|
|
/>
|
|
<!-- #endif -->
|
|
</page-meta>
|
|
<view class="search flex flex-col min-h-0 h-full">
|
|
<!-- #ifndef H5 -->
|
|
<u-sticky h5-nav-height="0" bg-color="transparent">
|
|
<u-navbar
|
|
:is-back="true"
|
|
:is-fixed="true"
|
|
:border-bottom="false"
|
|
title="搜索"
|
|
title-color="#000"
|
|
:title-bold="false"
|
|
:background="{ background: `rgba(256,256, 256, ${search.searching ? 1 : 0})` }"
|
|
>
|
|
</u-navbar>
|
|
</u-sticky>
|
|
<!-- #endif -->
|
|
|
|
<!-- 搜索框 --- 未搜索 -->
|
|
<view
|
|
class="p-[30rpx]"
|
|
:style="{
|
|
'background-color': !search.searching ? 'transparent' : '#ffffff'
|
|
}"
|
|
>
|
|
<view
|
|
class="search-input flex"
|
|
:style="{
|
|
'background-color': !search.searching ? '#ffffff' : '#F6F7F8'
|
|
}"
|
|
>
|
|
<view class="search-input-icon flex items-center flex-none">
|
|
<u-icon name="search"></u-icon>
|
|
</view>
|
|
<view class="search-input-wrapper flex items-center flex-1">
|
|
<input
|
|
class="search-input-inner flex-1"
|
|
placeholder="请输入关键词"
|
|
v-model="keyword"
|
|
@confirm="handleSearch"
|
|
@change="handleSearch"
|
|
:focus="true"
|
|
/>
|
|
<view
|
|
v-if="keyword.length"
|
|
class="flex-none px-3 text-muted"
|
|
@click="clearSearch"
|
|
>
|
|
<u-icon name="close-circle" size="34"></u-icon>
|
|
</view>
|
|
</view>
|
|
|
|
<button
|
|
class="search-input-btn flex-none"
|
|
@click="handleSearch"
|
|
>
|
|
搜索
|
|
</button>
|
|
</view>
|
|
</view>
|
|
|
|
|
|
<!-- 搜索 -->
|
|
<view class="search-content flex flex-col min-h-0 h-full">
|
|
<!-- 未搜索 -->
|
|
<suggest
|
|
v-show="!search.searching"
|
|
:hot_search="search.hot_search"
|
|
:his_search="search.his_search"
|
|
@clear="handleClear"
|
|
@search="(val) => {
|
|
keyword = val;
|
|
handleSearch()
|
|
}"
|
|
></suggest>
|
|
|
|
<!-- 搜索结果 -->
|
|
<view
|
|
class="flex flex-col min-h-0 h-full"
|
|
v-show="search.searching"
|
|
>
|
|
<!-- 检索下拉组件 列表 -->
|
|
<view class="bg-white">
|
|
<u-dropdown
|
|
ref="uDropdownRef"
|
|
menu-icon="arrow-down-fill"
|
|
menu-icon-size="20"
|
|
border-radius="18"
|
|
duration="0"
|
|
:active-color="$theme.primaryColor"
|
|
>
|
|
<u-dropdown-item :title="sortOptions[sort].label">
|
|
<view class="bg-white rounded-b-xl pt-4">
|
|
<view
|
|
v-for="(item, index) in sortOptions"
|
|
:key="index"
|
|
class="pb-4 text-content"
|
|
:class="{
|
|
'text-primary': index === sort
|
|
}"
|
|
@click="handleFiltrate('sort', index)"
|
|
>
|
|
<text class="ml-4">
|
|
{{ item.label }}
|
|
</text>
|
|
</view>
|
|
</view>
|
|
</u-dropdown-item>
|
|
<u-dropdown-item
|
|
title="销量"
|
|
>
|
|
<view class="bg-white rounded-b-xl pt-4">
|
|
<view
|
|
v-for="(item, index) in salesOptions"
|
|
:key="index"
|
|
class="pb-4 text-content"
|
|
:class="{
|
|
'text-primary': item.value === order_sales
|
|
}"
|
|
@click="handleFiltrate('order_sales', item.value)"
|
|
>
|
|
<text class="ml-4">
|
|
{{ item.label }}
|
|
</text>
|
|
</view>
|
|
</view>
|
|
</u-dropdown-item>
|
|
<u-dropdown-item
|
|
title="价格"
|
|
>
|
|
<view class="bg-white rounded-b-xl pt-4">
|
|
<view
|
|
v-for="(item, index) in salesOptions"
|
|
:key="index"
|
|
class="pb-4 text-content"
|
|
:class="{
|
|
'text-primary': item.value === price
|
|
}"
|
|
@click="handleFiltrate('price', item.value)"
|
|
>
|
|
<text class="ml-4">
|
|
{{ item.label }}
|
|
</text>
|
|
</view>
|
|
</view>
|
|
</u-dropdown-item>
|
|
<u-dropdown-item
|
|
:title="listOptions[list].label"
|
|
>
|
|
<view class="bg-white rounded-b-xl pt-4">
|
|
<view
|
|
v-for="(item, index) in listOptions"
|
|
:key="index"
|
|
class="pb-4 pl-4 text-content"
|
|
:class="{
|
|
'text-primary': item.value === list
|
|
}"
|
|
@click="handleFiltrate('list', item.value)"
|
|
>
|
|
<u-icon
|
|
:name="item.icon"
|
|
size="28"
|
|
></u-icon>
|
|
<text class="ml-2">
|
|
{{ item.label }}展示
|
|
</text>
|
|
</view>
|
|
</view>
|
|
</u-dropdown-item>
|
|
</u-dropdown>
|
|
</view>
|
|
|
|
<!-- 显示页面 列表 -->
|
|
<view class="h-full">
|
|
<z-paging
|
|
ref="paging"
|
|
v-model="search.result.content.goods_list"
|
|
:fixed="false"
|
|
height="100%"
|
|
:empty-view-img="EmptySearch"
|
|
@query="queryList"
|
|
>
|
|
<area-goods
|
|
:content="search.result.content"
|
|
:styles="search.result.styles"
|
|
/>
|
|
</z-paging>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import {ref, reactive, shallowRef} from 'vue'
|
|
import Suggest from './component/suggest.vue'
|
|
import {HISTORY} from '@/enums/constantEnums'
|
|
import {getHotSearch, getServiceList} from '@/api/shop'
|
|
import {locationState} from "@/hooks/useLocation";
|
|
import cache from '@/utils/cache'
|
|
import AreaGoods from "@/components/widgets/area-goods/area-goods.vue";
|
|
import EmptySearch from "@/static/images/empty/search.png";
|
|
|
|
interface Search {
|
|
hot_search: {
|
|
data: any[]
|
|
status: number
|
|
}
|
|
his_search: string[]
|
|
result: any
|
|
searching: boolean
|
|
}
|
|
|
|
const search = reactive<Search>({
|
|
hot_search: {
|
|
data: [],
|
|
status: 1
|
|
},
|
|
his_search: [],
|
|
// 这里复用了首页装修的商品组组件数据。
|
|
result: {
|
|
content: {
|
|
enabled: 1, // 是否启用
|
|
type: 1, // 1-自动获取
|
|
goods_type: 1, // 1-单列 2-双列 3-横向滑动 4-大图模式
|
|
show_title: 1, // 商品标题
|
|
show_server: 1, // 服务
|
|
show_price: 1, // 商品价格
|
|
show_scribing_price: 1, // 划线价格
|
|
show_sales: 1, // 销量
|
|
|
|
btn_text: '立即下单', // 按钮文字
|
|
show_num: 1, // 显示数量
|
|
goods_list: [] // 商品数据
|
|
},
|
|
styles: {
|
|
title_color: '#000000', // 标题颜色
|
|
server_color: '#888888', // 服务颜色
|
|
price_color: '#fc5447', // 价格颜色
|
|
scribing_price_color: '#888888', // 划线价格颜色
|
|
sales_color: '#888888', // 销量颜色
|
|
btn_radius: 10, // 按钮圆角
|
|
|
|
root_bg_color: '', // 根背景颜色
|
|
component_bg_color: '#ffffff', // 组件背景颜色
|
|
goods_bg_color: '', // 商品背景颜色
|
|
padding_top: 12, // 上内边距
|
|
padding_horizontal: 12, // 左右内边距
|
|
padding_bottom: 12, // 下内边距
|
|
goods_horizontal: 12, // 商品左右内边距
|
|
goods_vertical: 12, // 商品上下内边距
|
|
|
|
border_top_radius: 20,
|
|
border_bottom_radius: 20,
|
|
image_radius: 8
|
|
}
|
|
},
|
|
searching: false
|
|
})
|
|
const keyword = ref<string>('')
|
|
const order_sales = ref('') // 销量排序
|
|
const price = ref('') // 价格排序
|
|
const sort = ref('') // 综合排序
|
|
const list = ref('card') // 列表展示
|
|
const paging = shallowRef()
|
|
const uDropdownRef = shallowRef()
|
|
|
|
const sortOptions = {
|
|
'': {value: '', label: '综合排序'},
|
|
// 'desc': { value: 'desc', label:'距离优先'},
|
|
// 'asc': {value: 'asc', label: '销量优先'},
|
|
'comment_sales': {value: 'desc', label: '好评优先'}
|
|
}
|
|
const salesOptions = [
|
|
{value: '', label: '默认'},
|
|
{value: 'desc', label: '从高到低'},
|
|
{value: 'asc', label: '从低到高'}
|
|
]
|
|
const listOptions = {
|
|
card: {value: 'card', icon: 'grid', label: '卡片'},
|
|
list: {value: 'list', icon: 'list-dot', label: '列表'}
|
|
}
|
|
|
|
const handleFiltrate = (type: string, value: string) => {
|
|
switch (type) {
|
|
case 'sort':
|
|
sort.value = value
|
|
paging.value.refresh()
|
|
break
|
|
case 'order_sales':
|
|
order_sales.value = value
|
|
paging.value.refresh()
|
|
break
|
|
case 'price':
|
|
price.value = value
|
|
paging.value.refresh()
|
|
break
|
|
case 'list':
|
|
list.value = value
|
|
value === 'card' ? (search.result.content.goods_type = 1) : (search.result.content.goods_type = 2)
|
|
break
|
|
}
|
|
uDropdownRef.value?.close()
|
|
}
|
|
|
|
const handleSearch = () => {
|
|
if (keyword.value.trim() === '') {
|
|
return
|
|
}
|
|
if (keyword.value) {
|
|
if (!search.his_search.includes(keyword.value)) {
|
|
search.his_search.unshift(keyword.value)
|
|
cache.set(HISTORY, search.his_search)
|
|
}
|
|
}
|
|
paging.value.reload()
|
|
search.searching = true
|
|
}
|
|
|
|
const clearSearch = () => {
|
|
keyword.value = ''
|
|
search.searching = false
|
|
}
|
|
|
|
const getHotSearchFunc = async () => {
|
|
try {
|
|
search.hot_search = await getHotSearch()
|
|
} catch (e) {
|
|
//TODO handle the exception
|
|
console.log('获取热门搜索失败=>', e)
|
|
}
|
|
}
|
|
|
|
const handleClear = async (): Promise<void> => {
|
|
const resModel: any = await uni.showModal({
|
|
title: '温馨提示',
|
|
content: '是否清空历史记录?'
|
|
})
|
|
if (resModel.confirm) {
|
|
cache.set(HISTORY, '')
|
|
search.his_search = []
|
|
}
|
|
}
|
|
|
|
const queryList = async (page_no: number, page_size: number) => {
|
|
try {
|
|
const {lists} = await getServiceList({
|
|
keyword: keyword.value,
|
|
city_id: locationState.city_id,
|
|
order_sales: order_sales.value,
|
|
price: price.value,
|
|
comment_sales: sort.value,
|
|
page_no,
|
|
page_size
|
|
})
|
|
paging.value.complete(lists)
|
|
} catch (e) {
|
|
console.log('报错=>', e)
|
|
//TODO handle the exception
|
|
paging.value.complete(false)
|
|
}
|
|
}
|
|
|
|
getHotSearchFunc()
|
|
search.his_search = cache.get(HISTORY) || []
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.search {
|
|
.search-input {
|
|
background-color: #ffffff;
|
|
border-radius: 50px;
|
|
padding: 10rpx 20rpx;
|
|
|
|
.search-input-icon {
|
|
color: #666666;
|
|
padding: 0 14rpx 0 14rpx;
|
|
}
|
|
|
|
.search-input-wrapper {
|
|
|
|
}
|
|
|
|
.search-input-inner {
|
|
|
|
}
|
|
|
|
.search-input-btn {
|
|
height: 60rpx;
|
|
line-height: 60rpx;
|
|
font-size: 28rpx;
|
|
@apply bg-primary text-white rounded-full;
|
|
}
|
|
}
|
|
|
|
&-content {
|
|
|
|
&-s {
|
|
height: 100%;
|
|
}
|
|
}
|
|
}
|
|
</style>
|