<template>
|
<view class="search-container">
|
<!-- 搜索栏 -->
|
<view class="search-bar">
|
<view class="search-box">
|
<text class="iconfont icon-search"></text>
|
<input
|
type="text"
|
v-model="searchKey"
|
:placeholder="$t('common.search.placeholder')"
|
@confirm="handleSearch"
|
focus
|
/>
|
<text class="clear" @tap="clearSearch" v-if="searchKey">×</text>
|
</view>
|
<text class="cancel" @tap="goBack">{{ $t('common.search.cancel') }}</text>
|
</view>
|
|
<!-- 搜索历史 -->
|
<view class="history-section" v-if="!searchKey && searchHistory.length">
|
<view class="section-header">
|
<text class="title">{{ $t('common.search.history') }}</text>
|
<text class="clear" @tap="clearHistory">{{ $t('common.search.clear') }}</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="text">{{ item }}</text>
|
<text class="delete" @tap.stop="deleteHistory(index)">×</text>
|
</view>
|
</view>
|
</view>
|
|
<!-- 热门搜索 -->
|
<view class="hot-section" v-if="!searchKey">
|
<view class="section-title">{{ $t('common.search.hot') }}</view>
|
<view class="hot-tags">
|
<view
|
class="tag"
|
v-for="(tag, index) in hotSearches"
|
:key="index"
|
@tap="useHotSearch(tag)"
|
:class="{ hot: index < 3 }"
|
>
|
{{ tag }}
|
</view>
|
</view>
|
</view>
|
|
<!-- 搜索建议 -->
|
<view class="suggest-list" v-if="searchKey && !showResults">
|
<view
|
class="suggest-item"
|
v-for="(item, index) in suggestions"
|
:key="index"
|
@tap="useSuggestion(item)"
|
>
|
<text class="iconfont icon-search"></text>
|
<text class="text">{{ item }}</text>
|
</view>
|
</view>
|
|
<!-- 搜索结果 -->
|
<view class="result-container" v-if="showResults">
|
<!-- 结果分类 -->
|
<view class="result-tabs">
|
<view
|
class="tab-item"
|
v-for="(tab, index) in resultTabs"
|
:key="index"
|
:class="{ active: currentTab === tab.value }"
|
@tap="switchTab(tab.value)"
|
>
|
<text class="label">{{ $t(`department.search.tabs.${tab.value}`) }}</text>
|
<text class="count">({{ tab.count }})</text>
|
</view>
|
</view>
|
|
<!-- 科室结果 -->
|
<view class="department-list" v-if="currentTab === 'department'">
|
<view
|
class="department-item card"
|
v-for="(dept, index) in departmentResults"
|
:key="index"
|
@tap="navigateToDepartment(dept)"
|
>
|
<view class="header">
|
<view class="hospital">
|
<image :src="dept.hospitalLogo" mode="aspectFit" class="logo" />
|
<text class="name">{{ dept.hospitalName }}</text>
|
</view>
|
<view class="dept-info">
|
<image :src="dept.icon" mode="aspectFit" class="icon" />
|
<view class="info">
|
<text class="name">{{ dept.name }}</text>
|
<text class="desc">{{ dept.description }}</text>
|
</view>
|
</view>
|
</view>
|
<view class="footer">
|
<view class="stats">
|
<text class="distance">{{ dept.distance }}km</text>
|
<text class="rating">评分 {{ dept.rating }}</text>
|
<text class="count">{{ dept.doctorCount }}位医生</text>
|
</view>
|
<button class="book-btn primary-btn">预约挂号</button>
|
</view>
|
</view>
|
</view>
|
|
<!-- 医生结果 -->
|
<view class="doctor-list" v-if="currentTab === 'doctor'">
|
<view
|
class="doctor-item card"
|
v-for="(doctor, index) in doctorResults"
|
:key="index"
|
@tap="navigateToDoctor(doctor)"
|
>
|
<image :src="doctor.avatar" mode="aspectFill" class="avatar" />
|
<view class="info">
|
<view class="basic">
|
<text class="name">{{ doctor.name }}</text>
|
<text class="title">{{ doctor.title }}</text>
|
</view>
|
<text class="department">{{ doctor.department }}</text>
|
<text class="specialty">{{ doctor.specialty }}</text>
|
<view class="footer">
|
<view class="rating">
|
<text class="score">{{ doctor.rating }}分</text>
|
<text class="count">{{ doctor.ratingCount }}评价</text>
|
</view>
|
<button class="book-btn primary-btn">预约</button>
|
</view>
|
</view>
|
</view>
|
</view>
|
|
<!-- 疾病结果 -->
|
<view class="disease-list" v-if="currentTab === 'disease'">
|
<view
|
class="disease-item card"
|
v-for="(disease, index) in diseaseResults"
|
:key="index"
|
@tap="navigateToDisease(disease)"
|
>
|
<text class="name">{{ disease.name }}</text>
|
<text class="desc">{{ disease.description }}</text>
|
<view class="departments">
|
<text class="label">就诊科室:</text>
|
<text
|
class="dept"
|
v-for="(dept, idx) in disease.departments"
|
:key="idx"
|
>{{ dept }}</text>
|
</view>
|
</view>
|
</view>
|
</view>
|
</view>
|
</template>
|
|
<script setup>
|
import { ref, computed } from 'vue'
|
|
// 搜索关键词
|
const searchKey = ref('')
|
const showResults = ref(false)
|
|
// 搜索历史
|
const searchHistory = ref([
|
'心内科',
|
'发烧',
|
'骨科',
|
'儿科'
|
])
|
|
// 热门搜索
|
const hotSearches = [
|
'心内科',
|
'儿科',
|
'发烧',
|
'骨科',
|
'高血压',
|
'糖尿病',
|
'感冒',
|
'头痛'
|
]
|
|
// 搜索建议
|
const suggestions = computed(() => {
|
if (!searchKey.value) return []
|
return [
|
searchKey.value + '科',
|
'儿童' + searchKey.value,
|
searchKey.value + '专科',
|
searchKey.value + '疾病'
|
]
|
})
|
|
// 结果分类
|
const resultTabs = [
|
{ value: 'department', count: 5 },
|
{ value: 'doctor', count: 8 },
|
{ value: 'disease', count: 3 }
|
]
|
|
const currentTab = ref('department')
|
|
// 搜索结果数据
|
const departmentResults = ref([
|
{
|
id: 1,
|
name: '心内科',
|
icon: '/static/department/cardiology.png',
|
description: '心血管疾病诊治',
|
rating: 4.9,
|
doctorCount: 8,
|
hospitalId: 1,
|
hospitalName: '青岛镜湖医院',
|
hospitalLogo: '/static/hospital/kiang-wu.jpg',
|
distance: 2.5
|
},
|
{
|
id: 2,
|
name: '心内科',
|
icon: '/static/department/cardiology.png',
|
description: '心血管疾病诊治',
|
rating: 4.8,
|
doctorCount: 6,
|
hospitalId: 2,
|
hospitalName: '青岛科大医院',
|
hospitalLogo: '/static/hospital/must.jpg',
|
distance: 5.8
|
}
|
])
|
|
const doctorResults = ref([
|
{
|
id: 1,
|
name: '张医生',
|
title: '主任医师',
|
avatar: '/static/doctor/doctor1.jpg',
|
department: '心内科',
|
specialty: '冠心病、心律失常',
|
rating: 4.9,
|
ratingCount: 1280
|
}
|
])
|
|
const diseaseResults = ref([
|
{
|
id: 1,
|
name: '冠心病',
|
description: '心脏冠状动脉血管发生动脉粥样硬化病变而引起的心脏病',
|
departments: ['心内科', '心外科']
|
}
|
])
|
|
// 清空搜索
|
const clearSearch = () => {
|
searchKey.value = ''
|
showResults.value = false
|
}
|
|
// 返回上一页
|
const goBack = () => {
|
uni.navigateBack()
|
}
|
|
// 清空历史
|
const clearHistory = () => {
|
uni.showModal({
|
title: '提示',
|
content: '确定要清空搜索历史吗?',
|
success: (res) => {
|
if (res.confirm) {
|
searchHistory.value = []
|
}
|
}
|
})
|
}
|
|
// 删除单条历史
|
const deleteHistory = (index) => {
|
searchHistory.value.splice(index, 1)
|
}
|
|
// 使用历史记录
|
const useHistory = (keyword) => {
|
searchKey.value = keyword
|
handleSearch()
|
}
|
|
// 使用热门搜索
|
const useHotSearch = (keyword) => {
|
searchKey.value = keyword
|
handleSearch()
|
}
|
|
// 使用搜索建议
|
const useSuggestion = (keyword) => {
|
searchKey.value = keyword
|
handleSearch()
|
}
|
|
// 执行搜索
|
const handleSearch = () => {
|
if (!searchKey.value.trim()) return
|
|
// 添加到搜索历史
|
if (!searchHistory.value.includes(searchKey.value)) {
|
searchHistory.value.unshift(searchKey.value)
|
if (searchHistory.value.length > 10) {
|
searchHistory.value.pop()
|
}
|
}
|
|
showResults.value = true
|
// 加载搜索结果
|
loadSearchResults()
|
}
|
|
// 切换结果分类
|
const switchTab = (tab) => {
|
currentTab.value = tab
|
}
|
|
// 加载搜索结果
|
const loadSearchResults = () => {
|
// 加载搜索结果的逻辑
|
}
|
|
// 导航到科室详情
|
const navigateToDepartment = (dept) => {
|
uni.navigateTo({
|
url: `/pages/department/detail?id=${dept.id}&hospitalId=${dept.hospitalId}`
|
})
|
}
|
|
// 导航到医生详情
|
const navigateToDoctor = (doctor) => {
|
uni.navigateTo({
|
url: `/pages/appointment/doctor?doctorId=${doctor.id}`
|
})
|
}
|
|
// 导航到疾病详情
|
const navigateToDisease = (disease) => {
|
uni.navigateTo({
|
url: `/pages/disease/detail?id=${disease.id}`
|
})
|
}
|
</script>
|
|
<style lang="scss">
|
.search-container {
|
min-height: 100vh;
|
background: $bg-color;
|
|
.search-bar {
|
display: flex;
|
align-items: center;
|
padding: 20rpx 30rpx;
|
background: #fff;
|
position: sticky;
|
top: 0;
|
z-index: 100;
|
box-shadow: $shadow-sm;
|
|
.search-box {
|
flex: 1;
|
display: flex;
|
align-items: center;
|
height: 72rpx;
|
background: $bg-color;
|
border-radius: $radius-xl;
|
padding: 0 30rpx;
|
margin-right: 20rpx;
|
|
.icon-search {
|
font-size: 32rpx;
|
color: $text-secondary;
|
margin-right: 20rpx;
|
}
|
|
input {
|
flex: 1;
|
font-size: 28rpx;
|
color: $text-primary;
|
}
|
|
.clear {
|
font-size: 40rpx;
|
color: $text-secondary;
|
padding: 0 10rpx;
|
}
|
}
|
|
.cancel {
|
font-size: 28rpx;
|
color: $text-regular;
|
padding: 10rpx;
|
}
|
}
|
|
.history-section {
|
background: #fff;
|
margin: 20rpx;
|
padding: 30rpx;
|
border-radius: $radius-lg;
|
|
.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 {
|
font-size: 26rpx;
|
color: $text-secondary;
|
padding: 10rpx;
|
}
|
}
|
|
.history-list {
|
.history-item {
|
display: flex;
|
align-items: center;
|
padding: 20rpx 0;
|
|
.icon-time {
|
font-size: 32rpx;
|
color: $text-secondary;
|
margin-right: 20rpx;
|
}
|
|
.text {
|
flex: 1;
|
font-size: 28rpx;
|
color: $text-regular;
|
}
|
|
.delete {
|
font-size: 40rpx;
|
color: $text-secondary;
|
padding: 0 10rpx;
|
}
|
}
|
}
|
}
|
|
.hot-section {
|
background: #fff;
|
margin: 20rpx;
|
padding: 30rpx;
|
border-radius: $radius-lg;
|
|
.section-title {
|
font-size: 32rpx;
|
color: $text-primary;
|
font-weight: bold;
|
margin-bottom: 20rpx;
|
}
|
|
.hot-tags {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 20rpx;
|
|
.tag {
|
font-size: 26rpx;
|
color: $text-regular;
|
padding: 12rpx 24rpx;
|
background: $bg-color;
|
border-radius: $radius-xl;
|
|
&.hot {
|
color: #fff;
|
background: $primary-gradient;
|
}
|
}
|
}
|
}
|
|
.suggest-list {
|
background: #fff;
|
|
.suggest-item {
|
display: flex;
|
align-items: center;
|
padding: 30rpx;
|
border-bottom: 1rpx solid #eee;
|
|
.icon-search {
|
font-size: 32rpx;
|
color: $text-secondary;
|
margin-right: 20rpx;
|
}
|
|
.text {
|
font-size: 28rpx;
|
color: $text-regular;
|
}
|
}
|
}
|
|
.result-container {
|
.result-tabs {
|
display: flex;
|
background: #fff;
|
padding: 20rpx 0;
|
margin-bottom: 20rpx;
|
box-shadow: $shadow-sm;
|
|
.tab-item {
|
flex: 1;
|
text-align: center;
|
position: relative;
|
|
&.active {
|
.label {
|
color: $primary-color;
|
font-weight: bold;
|
}
|
|
&::after {
|
content: '';
|
position: absolute;
|
left: 50%;
|
bottom: -20rpx;
|
transform: translateX(-50%);
|
width: 40rpx;
|
height: 4rpx;
|
background: $primary-color;
|
border-radius: 2rpx;
|
}
|
}
|
|
.label {
|
font-size: 28rpx;
|
color: $text-regular;
|
}
|
|
.count {
|
font-size: 24rpx;
|
color: $text-secondary;
|
margin-left: 4rpx;
|
}
|
}
|
}
|
|
.department-list, .doctor-list, .disease-list {
|
padding: 20rpx;
|
}
|
|
.department-item {
|
margin-bottom: 20rpx;
|
|
.header {
|
.hospital {
|
display: flex;
|
align-items: center;
|
padding-bottom: 20rpx;
|
margin-bottom: 20rpx;
|
border-bottom: 1rpx solid #eee;
|
|
.logo {
|
width: 40rpx;
|
height: 40rpx;
|
border-radius: $radius-sm;
|
margin-right: 12rpx;
|
}
|
|
.name {
|
font-size: 26rpx;
|
color: $text-regular;
|
}
|
}
|
|
.dept-info {
|
display: flex;
|
align-items: center;
|
margin-bottom: 20rpx;
|
|
.icon {
|
width: 80rpx;
|
height: 80rpx;
|
margin-right: 20rpx;
|
}
|
|
.info {
|
flex: 1;
|
|
.name {
|
font-size: 32rpx;
|
color: $text-primary;
|
font-weight: bold;
|
margin-bottom: 8rpx;
|
display: block;
|
}
|
|
.desc {
|
font-size: 26rpx;
|
color: $text-regular;
|
}
|
}
|
}
|
}
|
|
.footer {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
|
.stats {
|
.distance {
|
font-size: 26rpx;
|
color: $primary-color;
|
margin-right: 20rpx;
|
}
|
|
.rating {
|
font-size: 26rpx;
|
color: $warning;
|
margin-right: 20rpx;
|
}
|
|
.count {
|
font-size: 26rpx;
|
color: $text-secondary;
|
}
|
}
|
|
.book-btn {
|
width: 160rpx;
|
height: 60rpx;
|
line-height: 60rpx;
|
font-size: 26rpx;
|
}
|
}
|
}
|
|
.doctor-item {
|
display: flex;
|
margin-bottom: 20rpx;
|
padding: 20rpx;
|
|
.avatar {
|
width: 120rpx;
|
height: 120rpx;
|
border-radius: 60rpx;
|
margin-right: 20rpx;
|
}
|
|
.info {
|
flex: 1;
|
|
.basic {
|
margin-bottom: 8rpx;
|
|
.name {
|
font-size: 32rpx;
|
color: $text-primary;
|
font-weight: bold;
|
margin-right: 16rpx;
|
}
|
|
.title {
|
font-size: 26rpx;
|
color: $text-regular;
|
}
|
}
|
|
.department {
|
font-size: 26rpx;
|
color: $primary-color;
|
margin-bottom: 8rpx;
|
display: block;
|
}
|
|
.specialty {
|
font-size: 26rpx;
|
color: $text-regular;
|
margin-bottom: 16rpx;
|
display: block;
|
}
|
|
.footer {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
|
.rating {
|
.score {
|
font-size: 26rpx;
|
color: $warning;
|
font-weight: bold;
|
margin-right: 8rpx;
|
}
|
|
.count {
|
font-size: 24rpx;
|
color: $text-secondary;
|
}
|
}
|
|
.book-btn {
|
width: 120rpx;
|
height: 56rpx;
|
line-height: 56rpx;
|
font-size: 26rpx;
|
}
|
}
|
}
|
}
|
|
.disease-item {
|
margin-bottom: 20rpx;
|
padding: 20rpx;
|
|
.name {
|
font-size: 32rpx;
|
color: $text-primary;
|
font-weight: bold;
|
margin-bottom: 12rpx;
|
display: block;
|
}
|
|
.desc {
|
font-size: 26rpx;
|
color: $text-regular;
|
margin-bottom: 16rpx;
|
display: block;
|
}
|
|
.departments {
|
.label {
|
font-size: 26rpx;
|
color: $text-secondary;
|
}
|
|
.dept {
|
font-size: 26rpx;
|
color: $primary-color;
|
margin-right: 16rpx;
|
|
&:last-child {
|
margin-right: 0;
|
}
|
}
|
}
|
}
|
}
|
}
|
</style>
|