20260123
This commit is contained in:
@@ -1,13 +1,513 @@
|
||||
<template>
|
||||
<view>
|
||||
|
||||
<view class="search-page">
|
||||
<!-- 搜索头部 -->
|
||||
<view class="search-header" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||
<view class="search-bar-container">
|
||||
<!-- 返回按钮 -->
|
||||
<view class="back-btn" @click="goBack">
|
||||
<text class="back-icon">←</text>
|
||||
</view>
|
||||
|
||||
<!-- 搜索框 -->
|
||||
<view class="search-input-container">
|
||||
<view class="search-icon">🔍</view>
|
||||
<input
|
||||
class="search-input"
|
||||
type="text"
|
||||
:value="searchKeyword"
|
||||
@input="onInput"
|
||||
@confirm="onSearch"
|
||||
placeholder="请输入药品名称、症状或品牌"
|
||||
placeholder-class="placeholder"
|
||||
focus
|
||||
/>
|
||||
<view v-if="searchKeyword" class="clear-btn" @click="clearSearch">
|
||||
<text class="clear-icon">×</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索按钮 -->
|
||||
<view class="search-btn" @click="onSearch">
|
||||
<text class="search-btn-text">搜索</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 主内容区域 -->
|
||||
<scroll-view scroll-y class="main-content" :style="{ height: scrollHeight + 'px' }">
|
||||
<!-- 搜索历史 -->
|
||||
<view v-if="showHistory && searchHistory.length > 0" class="search-history">
|
||||
<view class="section-header">
|
||||
<text class="section-title">搜索历史</text>
|
||||
<text class="clear-history" @click="clearHistory">清空</text>
|
||||
</view>
|
||||
<view class="history-tags">
|
||||
<view
|
||||
v-for="(item, index) in searchHistory"
|
||||
:key="index"
|
||||
class="history-tag"
|
||||
@click="searchFromHistory(item)"
|
||||
>
|
||||
<text class="history-text">{{ item }}</text>
|
||||
<text class="delete-icon" @click.stop="deleteHistoryItem(index)">×</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 热门搜索 -->
|
||||
<view class="hot-search">
|
||||
<view class="section-header">
|
||||
<text class="section-title">热门搜索</text>
|
||||
</view>
|
||||
<view class="hot-tags">
|
||||
<view
|
||||
v-for="(item, index) in hotSearchList"
|
||||
:key="index"
|
||||
class="hot-tag"
|
||||
:class="{ 'hot': index < 3 }"
|
||||
@click="searchFromHot(item.keyword)"
|
||||
>
|
||||
<text class="hot-rank" v-if="index < 3">{{ index + 1 }}</text>
|
||||
<text class="hot-text">{{ item.keyword }}</text>
|
||||
<text v-if="item.hot" class="hot-icon">🔥</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索分类 -->
|
||||
<view class="search-categories">
|
||||
<view class="section-header">
|
||||
<text class="section-title">按分类搜索</text>
|
||||
</view>
|
||||
<view class="category-grid">
|
||||
<view
|
||||
v-for="category in searchCategories"
|
||||
:key="category.id"
|
||||
class="category-item"
|
||||
@click="searchByCategory(category)"
|
||||
>
|
||||
<view class="category-icon" :style="{ backgroundColor: category.color }">
|
||||
<text>{{ category.icon }}</text>
|
||||
</view>
|
||||
<text class="category-name">{{ category.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索建议 -->
|
||||
<view v-if="searchKeyword && searchSuggestions.length > 0" class="search-suggestions">
|
||||
<view class="suggestions-list">
|
||||
<view
|
||||
v-for="(suggestion, index) in searchSuggestions"
|
||||
:key="index"
|
||||
class="suggestion-item"
|
||||
@click="selectSuggestion(suggestion)"
|
||||
>
|
||||
<view class="suggestion-icon">🔍</view>
|
||||
<text class="suggestion-text">{{ suggestion }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索结果 -->
|
||||
<view v-if="showResults" class="search-results">
|
||||
<view class="results-header">
|
||||
<text class="results-title">搜索结果</text>
|
||||
<text class="results-count">共{{ searchResults.length }}个结果</text>
|
||||
</view>
|
||||
|
||||
<view class="results-list">
|
||||
<view
|
||||
v-for="product in searchResults"
|
||||
:key="product.id"
|
||||
class="result-item"
|
||||
@click="viewProductDetail(product)"
|
||||
>
|
||||
<image class="product-image" :src="product.image" mode="aspectFill" />
|
||||
<view class="product-info">
|
||||
<text class="product-name">{{ product.name }}</text>
|
||||
<text class="product-spec">{{ product.specification }}</text>
|
||||
|
||||
<view class="product-meta">
|
||||
<text class="manufacturer">{{ product.manufacturer }}</text>
|
||||
<text class="sales">已售{{ product.sales }}</text>
|
||||
</view>
|
||||
|
||||
<view class="price-section">
|
||||
<view class="current-price">
|
||||
<text class="price-symbol">¥</text>
|
||||
<text class="price-value">{{ product.price }}</text>
|
||||
</view>
|
||||
<text v-if="product.originalPrice > product.price" class="original-price">
|
||||
¥{{ product.originalPrice }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="product-tags">
|
||||
<text v-if="product.tag" class="product-tag">{{ product.tag }}</text>
|
||||
<text v-if="product.featured" class="featured-tag">{{ product.featured }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<view v-if="loading" class="loading-more">
|
||||
<view class="loading-spinner"></view>
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<view v-if="!hasMore && searchResults.length > 0" class="no-more">
|
||||
<text class="no-more-text">--- 没有更多了 ---</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view v-if="showEmpty" class="empty-state">
|
||||
<view class="empty-icon">🔍</view>
|
||||
<text class="empty-title">暂无搜索结果</text>
|
||||
<text class="empty-desc">换个关键词试试吧</text>
|
||||
</view>
|
||||
|
||||
<!-- 安全区域 -->
|
||||
<view class="safe-area"></view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup lang="uts">
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
|
||||
// 响应式数据
|
||||
const statusBarHeight = ref(0)
|
||||
const scrollHeight = ref(0)
|
||||
const searchKeyword = ref('')
|
||||
const showHistory = ref(true)
|
||||
const showResults = ref(false)
|
||||
const showEmpty = ref(false)
|
||||
const loading = ref(false)
|
||||
const hasMore = ref(true)
|
||||
|
||||
// 搜索历史
|
||||
const searchHistory = ref<string[]>([
|
||||
'布洛芬',
|
||||
'感冒药',
|
||||
'维生素C',
|
||||
'口罩',
|
||||
'创可贴'
|
||||
])
|
||||
|
||||
// 热门搜索
|
||||
const hotSearchList = ref([
|
||||
{ keyword: '布洛芬缓释胶囊', hot: true },
|
||||
{ keyword: '连花清瘟胶囊', hot: true },
|
||||
{ keyword: '维生素C片', hot: true },
|
||||
{ keyword: '板蓝根颗粒', hot: false },
|
||||
{ keyword: '阿莫西林胶囊', hot: false },
|
||||
{ keyword: '口罩', hot: false },
|
||||
{ keyword: '体温计', hot: false },
|
||||
{ keyword: '创可贴', hot: false }
|
||||
])
|
||||
|
||||
// 搜索分类
|
||||
const searchCategories = ref([
|
||||
{ id: 'cold', name: '感冒发烧', icon: '🤧', color: '#2196F3' },
|
||||
{ id: 'stomach', name: '肠胃用药', icon: '🤢', color: '#4CAF50' },
|
||||
{ id: 'pain', name: '止痛消炎', icon: '💊', color: '#F44336' },
|
||||
{ id: 'skin', name: '皮肤用药', icon: '🤕', color: '#9C27B0' },
|
||||
{ id: 'vitamin', name: '维生素', icon: '🍊', color: '#FF9800' },
|
||||
{ id: 'chronic', name: '慢性病', icon: '🫀', color: '#795548' },
|
||||
{ id: 'child', name: '儿童用药', icon: '👶', color: '#00BCD4' },
|
||||
{ id: 'external', name: '外用药品', icon: '🧴', color: '#8BC34A' }
|
||||
])
|
||||
|
||||
// 搜索建议
|
||||
const searchSuggestions = computed(() => {
|
||||
if (!searchKeyword.value) return []
|
||||
|
||||
const keyword = searchKeyword.value.toLowerCase()
|
||||
const suggestions = [
|
||||
'布洛芬缓释胶囊',
|
||||
'布洛芬颗粒',
|
||||
'布洛芬混悬液',
|
||||
'感冒灵颗粒',
|
||||
'感冒清热颗粒',
|
||||
'维生素C咀嚼片',
|
||||
'维生素C泡腾片',
|
||||
'阿莫西林胶囊',
|
||||
'连花清瘟胶囊',
|
||||
'板蓝根颗粒'
|
||||
]
|
||||
|
||||
return suggestions.filter(item =>
|
||||
item.toLowerCase().includes(keyword)
|
||||
).slice(0, 5)
|
||||
})
|
||||
|
||||
// 搜索结果
|
||||
const searchResults = ref<any[]>([])
|
||||
|
||||
// 模拟搜索结果数据
|
||||
const mockSearchResults = [
|
||||
{
|
||||
id: 'result1',
|
||||
name: '布洛芬缓释胶囊',
|
||||
specification: '0.3g*24粒',
|
||||
price: 18.5,
|
||||
originalPrice: 25.8,
|
||||
image: 'https://picsum.photos/300/300?random=search1',
|
||||
manufacturer: '修正药业',
|
||||
sales: 2560,
|
||||
tag: '热销',
|
||||
featured: '家庭常备'
|
||||
},
|
||||
{
|
||||
id: 'result2',
|
||||
name: '布洛芬颗粒',
|
||||
specification: '0.2g*12袋',
|
||||
price: 15.8,
|
||||
originalPrice: 20.0,
|
||||
image: 'https://picsum.photos/300/300?random=search2',
|
||||
manufacturer: '白云山',
|
||||
sales: 1890,
|
||||
tag: '推荐',
|
||||
featured: '儿童适用'
|
||||
},
|
||||
{
|
||||
id: 'result3',
|
||||
name: '感冒灵颗粒',
|
||||
specification: '10g*9袋',
|
||||
price: 22.5,
|
||||
originalPrice: 28.0,
|
||||
image: 'https://picsum.photos/300/300?random=search3',
|
||||
manufacturer: '999药业',
|
||||
sales: 3420,
|
||||
tag: '热销',
|
||||
featured: '快速缓解'
|
||||
},
|
||||
{
|
||||
id: 'result4',
|
||||
name: '维生素C咀嚼片',
|
||||
specification: '100mg*60片',
|
||||
price: 28.9,
|
||||
originalPrice: 35.0,
|
||||
image: 'https://picsum.photos/300/300?random=search4',
|
||||
manufacturer: '养生堂',
|
||||
sales: 1250,
|
||||
tag: '特价',
|
||||
featured: '增强免疫'
|
||||
}
|
||||
]
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
initPage()
|
||||
})
|
||||
|
||||
// 初始化页面
|
||||
const initPage = () => {
|
||||
const systemInfo = uni.getSystemInfoSync()
|
||||
statusBarHeight.value = systemInfo.statusBarHeight || 0
|
||||
|
||||
// 计算滚动区域高度
|
||||
const windowHeight = systemInfo.windowHeight
|
||||
const headerHeight = 100 // 搜索头部高度
|
||||
scrollHeight.value = windowHeight - headerHeight
|
||||
|
||||
// 从本地存储加载搜索历史
|
||||
loadSearchHistory()
|
||||
}
|
||||
|
||||
// 加载搜索历史
|
||||
const loadSearchHistory = () => {
|
||||
try {
|
||||
const history = uni.getStorageSync('searchHistory')
|
||||
if (history) {
|
||||
searchHistory.value = JSON.parse(history)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载搜索历史失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 保存搜索历史
|
||||
const saveSearchHistory = () => {
|
||||
try {
|
||||
uni.setStorageSync('searchHistory', JSON.stringify(searchHistory.value))
|
||||
} catch (error) {
|
||||
console.error('保存搜索历史失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 输入处理
|
||||
const onInput = (event: any) => {
|
||||
searchKeyword.value = event.detail.value
|
||||
showHistory.value = !searchKeyword.value
|
||||
showResults.value = false
|
||||
showEmpty.value = false
|
||||
}
|
||||
|
||||
// 清除搜索
|
||||
const clearSearch = () => {
|
||||
searchKeyword.value = ''
|
||||
showHistory.value = true
|
||||
showResults.value = false
|
||||
showEmpty.value = false
|
||||
}
|
||||
|
||||
// 执行搜索
|
||||
const onSearch = () => {
|
||||
if (!searchKeyword.value.trim()) {
|
||||
uni.showToast({
|
||||
title: '请输入搜索关键词',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 添加到搜索历史
|
||||
addToSearchHistory(searchKeyword.value.trim())
|
||||
|
||||
// 显示搜索结果
|
||||
performSearch()
|
||||
}
|
||||
|
||||
// 添加到搜索历史
|
||||
const addToSearchHistory = (keyword: string) => {
|
||||
// 移除重复项
|
||||
const index = searchHistory.value.indexOf(keyword)
|
||||
if (index !== -1) {
|
||||
searchHistory.value.splice(index, 1)
|
||||
}
|
||||
|
||||
// 添加到开头
|
||||
searchHistory.value.unshift(keyword)
|
||||
|
||||
// 限制历史记录数量
|
||||
if (searchHistory.value.length > 10) {
|
||||
searchHistory.value = searchHistory.value.slice(0, 10)
|
||||
}
|
||||
|
||||
// 保存到本地存储
|
||||
saveSearchHistory()
|
||||
}
|
||||
|
||||
// 从历史记录搜索
|
||||
const searchFromHistory = (keyword: string) => {
|
||||
searchKeyword.value = keyword
|
||||
performSearch()
|
||||
}
|
||||
|
||||
// 从热门搜索搜索
|
||||
const searchFromHot = (keyword: string) => {
|
||||
searchKeyword.value = keyword
|
||||
addToSearchHistory(keyword)
|
||||
performSearch()
|
||||
}
|
||||
|
||||
// 按分类搜索
|
||||
const searchByCategory = (category: any) => {
|
||||
searchKeyword.value = category.name
|
||||
addToSearchHistory(category.name)
|
||||
performSearch()
|
||||
}
|
||||
|
||||
// 选择搜索建议
|
||||
const selectSuggestion = (suggestion: string) => {
|
||||
searchKeyword.value = suggestion
|
||||
addToSearchHistory(suggestion)
|
||||
performSearch()
|
||||
}
|
||||
|
||||
// 执行搜索逻辑
|
||||
const performSearch = () => {
|
||||
showHistory.value = false
|
||||
showEmpty.value = false
|
||||
loading.value = true
|
||||
|
||||
// 模拟搜索延迟
|
||||
setTimeout(() => {
|
||||
if (searchKeyword.value.toLowerCase().includes('布洛芬') ||
|
||||
searchKeyword.value.toLowerCase().includes('感冒') ||
|
||||
searchKeyword.value.toLowerCase().includes('维生素')) {
|
||||
// 模拟搜索结果
|
||||
searchResults.value = [...mockSearchResults]
|
||||
showResults.value = true
|
||||
showEmpty.value = false
|
||||
} else {
|
||||
// 无结果
|
||||
searchResults.value = []
|
||||
showResults.value = false
|
||||
showEmpty.value = true
|
||||
}
|
||||
|
||||
loading.value = false
|
||||
hasMore.value = true
|
||||
|
||||
// 滚动到顶部
|
||||
uni.pageScrollTo({
|
||||
scrollTop: 0,
|
||||
duration: 300
|
||||
})
|
||||
}, 500)
|
||||
}
|
||||
|
||||
// 查看商品详情
|
||||
const viewProductDetail = (product: any) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/medicine/detail?id=${product.id}`
|
||||
})
|
||||
}
|
||||
|
||||
// 清空搜索历史
|
||||
const clearHistory = () => {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定要清空搜索历史吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
searchHistory.value = []
|
||||
saveSearchHistory()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 删除单个历史记录
|
||||
const deleteHistoryItem = (index: number) => {
|
||||
searchHistory.value.splice(index, 1)
|
||||
saveSearchHistory()
|
||||
}
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
// 加载更多
|
||||
const loadMore = () => {
|
||||
if (loading.value || !hasMore.value) return
|
||||
|
||||
loading.value = true
|
||||
|
||||
// 模拟加载更多数据
|
||||
setTimeout(() => {
|
||||
const newResults = [...mockSearchResults].map((item, idx) => ({
|
||||
...item,
|
||||
id: `more${idx}`,
|
||||
price: Math.floor(item.price * 0.9 + Math.random() * 10)
|
||||
}))
|
||||
|
||||
searchResults.value = [...searchResults.value, ...newResults]
|
||||
loading.value = false
|
||||
hasMore.value = searchResults.value.length < 20
|
||||
}, 1000)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
.search-page {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
background: #f8fafc;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe
|
||||
|
||||
Reference in New Issue
Block a user