<template>
|
<view class="search-container">
|
<!-- 搜索头部 -->
|
<view class="search-header">
|
<view class="search-box">
|
<text class="iconfont icon-search"></text>
|
<input
|
type="text"
|
v-model="keyword"
|
placeholder="搜索医院/科室/医生/疾病"
|
:focus="true"
|
@input="onSearch"
|
@confirm="onConfirm"
|
/>
|
<text
|
class="iconfont icon-close"
|
v-if="keyword"
|
@tap="clearKeyword"
|
></text>
|
</view>
|
<text class="cancel-btn" @tap="goBack">取消</text>
|
</view>
|
|
<!-- 搜索历史 -->
|
<view class="history-section" v-if="!keyword && searchHistory.length">
|
<view class="section-header">
|
<text class="title">搜索历史</text>
|
<text class="clear-btn" @tap="clearHistory">清空历史</text>
|
</view>
|
<view class="history-list">
|
<view
|
class="history-item"
|
v-for="(item, index) in searchHistory"
|
:key="index"
|
@tap="useHistory(item)"
|
>
|
<text class="iconfont icon-time"></text>
|
<text class="keyword">{{ item }}</text>
|
<text
|
class="delete"
|
@tap.stop="deleteHistory(index)"
|
>×</text>
|
</view>
|
</view>
|
</view>
|
|
<!-- 热门搜索 -->
|
<view class="hot-section" v-if="!keyword">
|
<view class="section-header">
|
<text class="title">热门搜索</text>
|
</view>
|
<view class="hot-list">
|
<view
|
class="hot-item"
|
v-for="(item, index) in hotSearches"
|
:key="index"
|
@tap="useHot(item)"
|
>
|
<text class="rank" :class="{ top: index < 3 }">{{ index + 1 }}</text>
|
<text class="keyword">{{ item.keyword }}</text>
|
<text class="count">{{ item.count }}次搜索</text>
|
</view>
|
</view>
|
</view>
|
|
<!-- 搜索建议 -->
|
<view class="suggest-section" v-if="keyword && suggests.length">
|
<view
|
class="suggest-item"
|
v-for="(item, index) in suggests"
|
:key="index"
|
@tap="selectSuggest(item)"
|
>
|
<text class="iconfont" :class="getTypeIcon(item.type)"></text>
|
<view class="info">
|
<text class="name">{{ item.name }}</text>
|
<text class="desc">{{ item.desc }}</text>
|
</view>
|
</view>
|
</view>
|
|
<!-- 搜索结果 -->
|
<view class="result-section" v-if="keyword && !suggests.length">
|
<view class="tab-bar">
|
<view
|
class="tab-item"
|
v-for="(tab, index) in tabs"
|
:key="index"
|
:class="{ active: currentTab === index }"
|
@tap="switchTab(index)"
|
>
|
<text>{{ tab.name }}</text>
|
<text class="count" v-if="tab.count">({{ tab.count }})</text>
|
</view>
|
</view>
|
|
<!-- 医院列表 -->
|
<scroll-view
|
v-if="currentTab === 0"
|
scroll-y
|
class="result-list"
|
@scrolltolower="loadMore"
|
>
|
<view
|
class="hospital-item"
|
v-for="(item, index) in hospitals"
|
:key="index"
|
@tap="viewHospital(item)"
|
>
|
<image :src="item.image" mode="aspectFill" class="hospital-image" />
|
<view class="info">
|
<text class="name">{{ item.name }}</text>
|
<text class="type">{{ item.type }}</text>
|
<view class="tags">
|
<text
|
v-for="(tag, idx) in item.tags"
|
:key="idx"
|
>{{ tag }}</text>
|
</view>
|
</view>
|
</view>
|
</scroll-view>
|
|
<!-- 科室列表 -->
|
<scroll-view
|
v-if="currentTab === 1"
|
scroll-y
|
class="result-list"
|
@scrolltolower="loadMore"
|
>
|
<view
|
class="department-item"
|
v-for="(item, index) in departments"
|
:key="index"
|
@tap="viewDepartment(item)"
|
>
|
<image :src="item.icon" mode="aspectFit" class="department-icon" />
|
<view class="info">
|
<text class="name">{{ item.name }}</text>
|
<text class="desc">{{ item.desc }}</text>
|
</view>
|
</view>
|
</scroll-view>
|
|
<!-- 医生列表 -->
|
<scroll-view
|
v-if="currentTab === 2"
|
scroll-y
|
class="result-list"
|
@scrolltolower="loadMore"
|
>
|
<view
|
class="doctor-item"
|
v-for="(item, index) in doctors"
|
:key="index"
|
@tap="viewDoctor(item)"
|
>
|
<image :src="item.avatar" mode="aspectFill" class="doctor-avatar" />
|
<view class="info">
|
<view class="name-title">
|
<text class="name">{{ item.name }}</text>
|
<text class="title">{{ item.title }}</text>
|
</view>
|
<text class="hospital">{{ item.hospital }}</text>
|
<text class="specialty">{{ item.specialty }}</text>
|
</view>
|
</view>
|
</scroll-view>
|
|
<!-- 疾病列表 -->
|
<scroll-view
|
v-if="currentTab === 3"
|
scroll-y
|
class="result-list"
|
@scrolltolower="loadMore"
|
>
|
<view
|
class="disease-item"
|
v-for="(item, index) in diseases"
|
:key="index"
|
@tap="viewDisease(item)"
|
>
|
<view class="info">
|
<text class="name">{{ item.name }}</text>
|
<text class="department">{{ item.department }}</text>
|
</view>
|
<text class="iconfont icon-arrow-right"></text>
|
</view>
|
</scroll-view>
|
</view>
|
</view>
|
</template>
|
|
<script setup>
|
import { ref } from 'vue'
|
|
// 搜索关键词
|
const keyword = ref('')
|
|
// 搜索历史
|
const searchHistory = ref([
|
'心内科',
|
'张医生',
|
'感冒发烧',
|
'镜湖医院'
|
])
|
|
// 热门搜索
|
const hotSearches = ref([
|
{ keyword: '新冠疫苗', count: 12580 },
|
{ keyword: '心内科', count: 8654 },
|
{ keyword: '儿科', count: 6532 },
|
{ keyword: '镜湖医院', count: 4521 },
|
{ keyword: '发烧咳嗽', count: 3654 }
|
])
|
|
// 搜索建议
|
const suggests = ref([])
|
|
// 搜索结果tabs
|
const tabs = ref([
|
{ name: '医院', count: 0 },
|
{ name: '科室', count: 0 },
|
{ name: '医生', count: 0 },
|
{ name: '疾病', count: 0 }
|
])
|
const currentTab = ref(0)
|
|
// 搜索结果列表
|
const hospitals = ref([])
|
const departments = ref([])
|
const doctors = ref([])
|
const diseases = ref([])
|
|
// 输入搜索
|
const onSearch = (e) => {
|
const value = e.detail.value.trim()
|
if (!value) {
|
suggests.value = []
|
return
|
}
|
|
// 这里调用搜索建议API
|
suggests.value = [
|
{
|
type: 'hospital',
|
name: '青岛镜湖医院',
|
desc: '三级甲等综合医院'
|
},
|
{
|
type: 'department',
|
name: '心内科',
|
desc: '心血管疾病诊治'
|
},
|
{
|
type: 'doctor',
|
name: '张医生',
|
desc: '主任医师 心内科'
|
}
|
]
|
}
|
|
// 确认搜索
|
const onConfirm = () => {
|
if (!keyword.value) return
|
suggests.value = []
|
|
// 保存搜索历史
|
if (!searchHistory.value.includes(keyword.value)) {
|
searchHistory.value.unshift(keyword.value)
|
if (searchHistory.value.length > 10) {
|
searchHistory.value.pop()
|
}
|
}
|
|
// 加载搜索结果
|
loadSearchResult()
|
}
|
|
// 加载搜索结果
|
const loadSearchResult = () => {
|
// 这里调用搜索API
|
hospitals.value = [
|
{
|
id: 1,
|
name: '青岛镜湖医院',
|
type: '三级甲等综合医院',
|
image: '/static/hospital/kiang-wu.jpg',
|
tags: ['综合医院', '24小时急诊']
|
}
|
]
|
departments.value = [
|
{
|
id: 1,
|
name: '心内科',
|
desc: '心血管疾病诊治',
|
icon: '/static/department/cardiology.png'
|
}
|
]
|
doctors.value = [
|
{
|
id: 1,
|
name: '张医生',
|
title: '主任医师',
|
avatar: '/static/doctor/avatar1.jpg',
|
hospital: '青岛镜湖医院',
|
specialty: '冠心病、高血压、心律失常'
|
}
|
]
|
diseases.value = [
|
{
|
id: 1,
|
name: '冠心病',
|
department: '心内科'
|
}
|
]
|
|
// 更新数量
|
tabs.value[0].count = hospitals.value.length
|
tabs.value[1].count = departments.value.length
|
tabs.value[2].count = doctors.value.length
|
tabs.value[3].count = diseases.value.length
|
}
|
|
// 切换标签
|
const switchTab = (index) => {
|
currentTab.value = index
|
}
|
|
// 加载更多
|
const loadMore = () => {
|
// 这里调用加载更多API
|
}
|
|
// 使用搜索历史
|
const useHistory = (keyword) => {
|
keyword.value = keyword
|
onConfirm()
|
}
|
|
// 删除搜索历史
|
const deleteHistory = (index) => {
|
searchHistory.value.splice(index, 1)
|
}
|
|
// 清空搜索历史
|
const clearHistory = () => {
|
uni.showModal({
|
title: '提示',
|
content: '确定要清空搜索历史吗?',
|
success: (res) => {
|
if (res.confirm) {
|
searchHistory.value = []
|
}
|
}
|
})
|
}
|
|
// 使用热门搜索
|
const useHot = (item) => {
|
keyword.value = item.keyword
|
onConfirm()
|
}
|
|
// 选择搜索建议
|
const selectSuggest = (item) => {
|
keyword.value = item.name
|
onConfirm()
|
}
|
|
// 获取类型图标
|
const getTypeIcon = (type) => {
|
const icons = {
|
hospital: 'icon-hospital',
|
department: 'icon-department',
|
doctor: 'icon-doctor',
|
disease: 'icon-disease'
|
}
|
return icons[type]
|
}
|
|
// 清除关键词
|
const clearKeyword = () => {
|
keyword.value = ''
|
suggests.value = []
|
}
|
|
// 返回
|
const goBack = () => {
|
uni.navigateBack()
|
}
|
|
// 查看详情
|
const viewHospital = (hospital) => {
|
uni.navigateTo({
|
url: `/pages/hospital/detail?id=${hospital.id}`
|
})
|
}
|
|
const viewDepartment = (department) => {
|
uni.navigateTo({
|
url: `/pages/department/detail?id=${department.id}`
|
})
|
}
|
|
const viewDoctor = (doctor) => {
|
uni.navigateTo({
|
url: `/pages/doctor/detail?id=${doctor.id}`
|
})
|
}
|
|
const viewDisease = (disease) => {
|
uni.navigateTo({
|
url: `/pages/disease/detail?id=${disease.id}`
|
})
|
}
|
</script>
|
|
<style lang="scss">
|
.search-container {
|
min-height: 100vh;
|
background: $bg-color;
|
padding-top: var(--status-bar-height);
|
|
.search-header {
|
display: flex;
|
align-items: center;
|
padding: 20rpx;
|
background: #fff;
|
|
.search-box {
|
flex: 1;
|
height: 72rpx;
|
background: $bg-color;
|
border-radius: $radius-xl;
|
display: flex;
|
align-items: center;
|
padding: 0 20rpx;
|
margin-right: 20rpx;
|
|
.iconfont {
|
font-size: 32rpx;
|
color: $text-secondary;
|
margin-right: 12rpx;
|
|
&.icon-close {
|
margin-right: 0;
|
margin-left: 12rpx;
|
}
|
}
|
|
input {
|
flex: 1;
|
height: 100%;
|
font-size: 28rpx;
|
}
|
}
|
|
.cancel-btn {
|
font-size: 28rpx;
|
color: $text-regular;
|
|
&:active {
|
opacity: 0.8;
|
}
|
}
|
}
|
|
.history-section,
|
.hot-section {
|
background: #fff;
|
margin-top: 20rpx;
|
padding: 30rpx;
|
|
.section-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 20rpx;
|
|
.title {
|
font-size: 32rpx;
|
color: $text-primary;
|
font-weight: bold;
|
}
|
|
.clear-btn {
|
font-size: 28rpx;
|
color: $text-secondary;
|
|
&:active {
|
opacity: 0.8;
|
}
|
}
|
}
|
}
|
|
.history-list {
|
.history-item {
|
display: flex;
|
align-items: center;
|
padding: 20rpx 0;
|
border-bottom: 1rpx solid #eee;
|
|
&:last-child {
|
border-bottom: none;
|
}
|
|
.iconfont {
|
font-size: 32rpx;
|
color: $text-secondary;
|
margin-right: 12rpx;
|
}
|
|
.keyword {
|
flex: 1;
|
font-size: 28rpx;
|
color: $text-regular;
|
}
|
|
.delete {
|
font-size: 40rpx;
|
color: $text-secondary;
|
padding: 0 20rpx;
|
|
&:active {
|
opacity: 0.8;
|
}
|
}
|
}
|
}
|
|
.hot-list {
|
.hot-item {
|
display: flex;
|
align-items: center;
|
padding: 20rpx 0;
|
border-bottom: 1rpx solid #eee;
|
|
&:last-child {
|
border-bottom: none;
|
}
|
|
.rank {
|
width: 40rpx;
|
font-size: 32rpx;
|
color: $text-secondary;
|
font-weight: bold;
|
|
&.top {
|
color: $danger;
|
}
|
}
|
|
.keyword {
|
flex: 1;
|
font-size: 28rpx;
|
color: $text-regular;
|
margin: 0 20rpx;
|
}
|
|
.count {
|
font-size: 24rpx;
|
color: $text-secondary;
|
}
|
}
|
}
|
|
.suggest-section {
|
background: #fff;
|
|
.suggest-item {
|
display: flex;
|
align-items: center;
|
padding: 30rpx;
|
border-bottom: 1rpx solid #eee;
|
|
&:last-child {
|
border-bottom: none;
|
}
|
|
.iconfont {
|
font-size: 40rpx;
|
color: $primary-color;
|
margin-right: 20rpx;
|
}
|
|
.info {
|
flex: 1;
|
|
.name {
|
font-size: 30rpx;
|
color: $text-primary;
|
margin-bottom: 4rpx;
|
display: block;
|
}
|
|
.desc {
|
font-size: 24rpx;
|
color: $text-secondary;
|
}
|
}
|
|
&:active {
|
background: $bg-color;
|
}
|
}
|
}
|
|
.result-section {
|
.tab-bar {
|
display: flex;
|
background: #fff;
|
padding: 0 30rpx;
|
border-bottom: 1rpx solid #eee;
|
|
.tab-item {
|
padding: 20rpx 30rpx;
|
font-size: 28rpx;
|
color: $text-regular;
|
position: relative;
|
|
.count {
|
font-size: 24rpx;
|
color: $text-secondary;
|
}
|
|
&.active {
|
color: $primary-color;
|
font-weight: bold;
|
|
&::after {
|
content: '';
|
position: absolute;
|
left: 50%;
|
bottom: 0;
|
transform: translateX(-50%);
|
width: 40rpx;
|
height: 4rpx;
|
background: $primary-color;
|
border-radius: 2rpx;
|
}
|
|
.count {
|
color: $primary-color;
|
}
|
}
|
}
|
}
|
|
.result-list {
|
height: calc(100vh - 300rpx);
|
|
.hospital-item {
|
display: flex;
|
padding: 30rpx;
|
background: #fff;
|
border-bottom: 1rpx solid #eee;
|
|
.hospital-image {
|
width: 160rpx;
|
height: 120rpx;
|
border-radius: $radius-lg;
|
margin-right: 20rpx;
|
}
|
|
.info {
|
flex: 1;
|
|
.name {
|
font-size: 32rpx;
|
color: $text-primary;
|
font-weight: bold;
|
margin-bottom: 8rpx;
|
display: block;
|
}
|
|
.type {
|
font-size: 26rpx;
|
color: $text-regular;
|
margin-bottom: 12rpx;
|
display: block;
|
}
|
|
.tags {
|
text {
|
display: inline-block;
|
font-size: 22rpx;
|
color: $primary-color;
|
background: $primary-light;
|
padding: 4rpx 12rpx;
|
border-radius: $radius-sm;
|
margin-right: 12rpx;
|
}
|
}
|
}
|
}
|
|
.department-item {
|
display: flex;
|
align-items: center;
|
padding: 30rpx;
|
background: #fff;
|
border-bottom: 1rpx solid #eee;
|
|
.department-icon {
|
width: 80rpx;
|
height: 80rpx;
|
margin-right: 20rpx;
|
}
|
|
.info {
|
flex: 1;
|
|
.name {
|
font-size: 30rpx;
|
color: $text-primary;
|
font-weight: bold;
|
margin-bottom: 4rpx;
|
display: block;
|
}
|
|
.desc {
|
font-size: 26rpx;
|
color: $text-regular;
|
}
|
}
|
}
|
|
.doctor-item {
|
display: flex;
|
padding: 30rpx;
|
background: #fff;
|
border-bottom: 1rpx solid #eee;
|
|
.doctor-avatar {
|
width: 120rpx;
|
height: 120rpx;
|
border-radius: 50%;
|
margin-right: 20rpx;
|
}
|
|
.info {
|
flex: 1;
|
|
.name-title {
|
margin-bottom: 8rpx;
|
|
.name {
|
font-size: 32rpx;
|
color: $text-primary;
|
font-weight: bold;
|
margin-right: 12rpx;
|
}
|
|
.title {
|
font-size: 26rpx;
|
color: $text-regular;
|
}
|
}
|
|
.hospital {
|
font-size: 26rpx;
|
color: $text-regular;
|
margin-bottom: 8rpx;
|
display: block;
|
}
|
|
.specialty {
|
font-size: 24rpx;
|
color: $text-secondary;
|
}
|
}
|
}
|
|
.disease-item {
|
display: flex;
|
align-items: center;
|
padding: 30rpx;
|
background: #fff;
|
border-bottom: 1rpx solid #eee;
|
|
.info {
|
flex: 1;
|
margin-right: 20rpx;
|
|
.name {
|
font-size: 30rpx;
|
color: $text-primary;
|
margin-bottom: 4rpx;
|
display: block;
|
}
|
|
.department {
|
font-size: 26rpx;
|
color: $text-regular;
|
}
|
}
|
|
.iconfont {
|
font-size: 32rpx;
|
color: $text-secondary;
|
}
|
}
|
}
|
}
|
}
|
</style>
|