Files
taimed-international-app/pages/course/search.vue

264 lines
5.4 KiB
Vue

<template>
<view class="search-page">
<!-- 导航栏 -->
<nav-bar>
<template #title>
<view class="search-box">
<wd-search
v-model="keyword"
hide-cancel
clearable
:placeholder="$t('courseSearch.placeholder')"
@search="handleSearch"
@clear="handleClear"
/>
</view>
</template>
</nav-bar>
<!-- 历史搜索区域 -->
<view v-if="!showResults" class="history-section">
<view class="history-title">{{ $t('courseSearch.historyTitle') }}</view>
<view class="history-tags">
<wd-tag
v-for="(item, index) in historyList"
:key="index"
@click="handleHistoryClick(item)"
>
{{ item }}
</wd-tag>
</view>
</view>
<!-- 搜索结果区域 -->
<view v-if="showResults" class="search-results">
<!-- 加载状态 -->
<view v-if="loading" class="loading-wrapper">
<wd-loading />
</view>
<!-- 课程列表 -->
<view v-if="!loading && courseList.length > 0" class="course-section">
<view class="course-list">
<list-item
v-for="(item, index) in courseList"
:key="index"
:data="item"
:showToDetail="false"
desc="content"
/>
</view>
</view>
<!-- 空状态 -->
<view v-if="!loading && isEmpty" class="empty-wrapper">
<wd-divider :text="$t('courseSearch.noData')" />
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import { courseApi } from '@/api/modules/course'
import type { ICourse } from '@/types/search'
import listItem from './list/components/list-item.vue'
const { t } = useI18n()
// 状态定义
const keyword = ref<string>('') // 搜索关键词
const historyList = ref<string[]>([]) // 历史搜索记录
const courseList = ref<ICourse[]>([]) // 课程列表
const showResults = ref<boolean>(false) // 是否显示搜索结果
const loading = ref<boolean>(false) // 加载状态
const isEmpty = ref<boolean>(false) // 是否为空结果
/**
* 获取历史搜索记录
*/
const getHistory = () => {
try {
let records = uni.getStorageSync('hisRecords') || []
records = [...new Set(records)]
if (records.length > 10) {
records = records.slice(0, 10)
}
historyList.value = records
uni.setStorageSync('hisRecords', records)
} catch (error) {
console.error('获取历史记录失败:', error)
historyList.value = []
}
}
/**
* 保存搜索记录
*/
const saveHistory = (kw: string) => {
try {
let records = uni.getStorageSync('hisRecords') || []
records.unshift(kw)
uni.setStorageSync('hisRecords', records)
} catch (error) {
console.error('保存历史记录失败:', error)
}
}
/**
* 执行搜索
*/
const handleSearch = async () => {
if (!keyword.value.trim()) {
uni.showToast({
icon: 'none',
title: t('courseSearch.pleaseInputKeyword')
})
return
}
loading.value = true
showResults.value = true
isEmpty.value = false
try {
const res = await courseApi.searchData({
title: keyword.value.trim()
})
if (res.code === 0) {
courseList.value = res.courseEntities || []
isEmpty.value = courseList.value.length === 0
// 保存搜索历史
saveHistory(keyword.value.trim())
} else {
courseList.value = []
isEmpty.value = true
}
} catch (error) {
console.error('搜索失败:', error)
uni.showToast({
icon: 'none',
title: t('global.networkConnectionError')
})
courseList.value = []
isEmpty.value = true
} finally {
loading.value = false
}
}
/**
* 点击历史标签搜索
*/
const handleHistoryClick = (item: string) => {
keyword.value = item
handleSearch()
}
/**
* 清空搜索
*/
const handleClear = () => {
keyword.value = ''
showResults.value = false
courseList.value = []
isEmpty.value = false
getHistory()
}
/**
* 页面挂载
*/
onMounted(() => {
getHistory()
})
/**
* 页面显示
*/
onShow(() => {
getHistory()
})
</script>
<style lang="scss" scoped>
.search-page {
min-height: 100vh;
background: #f7faf9;
}
.search-box {
display: flex;
height: 100%;
align-items: center;
width: 100%;
--wot-search-padding: 0;
--wot-search-side-padding: 0;
:deep(.wd-search) {
background: transparent;
width: 100%;
}
}
// 历史搜索样式
.history-section {
padding: 40rpx;
.history-title {
font-size: 30rpx;
font-weight: bold;
margin-bottom: 20rpx;
}
.history-tags {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
}
// 搜索结果样式
.search-results {
padding: 20rpx;
}
.loading-wrapper {
display: flex;
justify-content: center;
align-items: center;
padding: 100rpx 0;
}
.empty-wrapper {
display: flex;
justify-content: center;
align-items: center;
padding: 100rpx 0;
}
.section-title {
font-size: 40rpx;
color: #1e40af;
font-weight: bold;
letter-spacing: 2rpx;
margin-bottom: 30rpx;
text-shadow: 0 2rpx 4rpx rgba(0, 122, 255, 0.6);
}
// 课程列表样式
.course-section {
margin-bottom: 40rpx;
}
.course-list {
display: flex;
flex-direction: column;
gap: 20rpx;
}
</style>