Files
taimed-international-app/pages/book/search.vue
fuchao 64abd3d4ab revert 33c22eaad9
revert 解决冲突
2025-11-27 15:38:24 +08:00

295 lines
5.7 KiB
Vue

<template>
<view class="search-page">
<!-- 搜索栏 -->
<nav-bar>
<template #title>
<view class="search-box">
<wd-search
v-model="keyword"
hide-cancel
@search="handleSearch"
/>
</view>
</template>
</nav-bar>
<!-- 搜索结果 -->
<view class="search-results">
<view v-if="loading" class="loading-wrapper">
<wd-loading />
</view>
<view v-else-if="searchResults.length > 0" class="book-list">
<view
v-for="(item, index) in searchResults"
:key="index"
class="book-item"
@click="handleBookClick(item.bookId)"
>
<image :src="item.images" />
<text class="book-text">{{ item.name }}</text>
<text v-if="formatPrice(item)" class="book-price">{{
formatPrice(item)
}}</text>
<text v-if="formatStats(item)" class="book-flag">{{
formatStats(item)
}}</text>
</view>
</view>
<view v-else-if="isEmpty" class="empty-wrapper">
<wd-status-tip image="content" :tip="$t('global.searchNoResult')" />
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import { homeApi } from '@/api/modules/book_home'
import type { IBookWithStats, IVipInfo } from '@/types/home'
const { t } = useI18n()
// 状态定义
const notchHeight = ref(0)
const keyword = ref('')
const searchResults = ref<IBookWithStats[]>([])
const loading = ref(false)
const isEmpty = ref(false)
const vipInfo = ref<IVipInfo | null>(null)
// 获取URL参数
onLoad((options: any) => {
keyword.value = options.keyword
handleSearch()
})
/**
* 获取VIP信息
*/
const getVipInfo = async () => {
try {
const res = await homeApi.getVipInfo()
if (res.vipInfo) {
vipInfo.value = res.vipInfo
}
} catch (error) {
console.error('获取VIP信息失败:', error)
}
}
/**
* 处理搜索
*/
const handleSearch = async () => {
if (!keyword.value.trim()) {
return
}
loading.value = true
isEmpty.value = false
try {
const res = await homeApi.searchBooks({
title: keyword.value.trim(),
page: 1,
limit: 10,
})
if (res.bookList && res.bookList.length > 0) {
searchResults.value = res.bookList
isEmpty.value = false
} else {
searchResults.value = []
isEmpty.value = true
}
} catch (error) {
console.error('搜索失败:', error)
searchResults.value = []
isEmpty.value = true
} finally {
loading.value = false
}
}
/**
* 处理清空
*/
const handleClear = () => {
keyword.value = ''
searchResults.value = []
isEmpty.value = false
}
/**
* 处理图书点击
*/
const handleBookClick = (bookId: number) => {
uni.navigateTo({
url: `/pages/book/detail?id=${bookId}`
})
}
/**
* 格式化价格
*/
const formatPrice = (book: IBookWithStats): string => {
// 已购买不显示价格
if (book.isBuy) return ''
// VIP用户且图书为VIP专享
if (vipInfo.value?.id && book.isVip === '2') {
const price = book.sysDictData?.dictValue
return price ? `$ ${price} NZD` : ''
}
// 普通用户
if (!vipInfo.value?.id) {
const price = book.sysDictData?.dictValue
return price ? `$ ${price} NZD` : ''
}
return ''
}
/**
* 格式化统计信息
*/
const formatStats = (book: IBookWithStats): string => {
if (book.readCount && book.readCount > 0) {
return `${book.readCount}${t('bookHome.readingCount')}`
}
if (book.buyCount && book.buyCount > 0) {
return `${book.buyCount}${t('bookHome.purchased')}`
}
return ''
}
/**
* 页面加载
*/
onMounted(async () => {
// 获取刘海高度
const systemInfo = uni.getSystemInfoSync()
notchHeight.value = systemInfo.safeArea.top
// 获取VIP信息
await getVipInfo()
})
</script>
<style lang="scss" scoped>
.search-page {
min-height: 100vh;
background: #f7faf9;
}
.search-box {
display: flex;
height: 100%;
align-items: center;
--wot-search-padding: 0;
--wot-search-side-padding: 0;
:deep() {
.wd-search {
background: transparent;
width: 100%;
}
}
}
.search-header {
background: #fff;
padding: 20rpx;
padding-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
.search-bar-wrapper {
display: flex;
align-items: center;
.back-icon {
margin-right: 20rpx;
flex-shrink: 0;
}
.search-input {
flex: 1;
}
}
}
.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;
}
.book-list {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
.book-item {
width: 49%;
background-color: #fff;
border-radius: 15rpx;
height: 575rpx;
position: relative;
margin-bottom: 20rpx;
image {
width: 85%;
margin: 25rpx auto 0;
border-radius: 15rpx;
height: 380rpx;
display: block;
}
.book-text {
display: block;
font-size: 28rpx;
color: #333;
line-height: 36rpx;
width: 80%;
margin: 15rpx auto 0;
max-height: 72rpx;
overflow: hidden;
}
.book-price {
position: absolute;
font-size: 28rpx;
color: #ff4703;
left: 30rpx;
bottom: 20rpx;
}
.book-flag {
display: block;
font-size: 26rpx;
color: #999;
position: absolute;
right: 6%;
bottom: 20rpx;
}
}
}
</style>