jihua-search.vue 3.97 KB
<template>
	<view class="search-page">
		<view class="search-header">
			<up-search v-model="searchKeyword" placeholder="搜索训练计划" placeholderColor="#999" shape="round"
				:showAction="true" actionText="取消" :clearabled="true" @search="handleSearch" @custom="handleSearch"
				@cancel="handleCancel" />
		</view>

		<scroll-view class="search-results" scroll-y enable-flex>
			<up-empty v-if="!hasSearched" text="请输入关键词搜索训练计划" mode="search" />
			<up-empty v-else-if="searchResults.length === 0" text="未找到相关训练计划" mode="data" />
			<view v-else class="results-list">
				<view v-for="plan in searchResults" :key="plan.id" class="result-item" @click="goToDetail(plan)">
					<image v-if="plan.cover" :src="plan.cover" class="result-cover" mode="aspectFill" />
					<view class="result-info">
						<text class="result-title">{{ plan.title }}</text>
						<text class="result-meta" v-if="plan.meta">{{ plan.meta }}</text>
					</view>
				</view>
			</view>
		</scroll-view>
	</view>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue';
import QueryPlanApi from '@/sheep/api/plan/queryplan';
import { getNavbarHeight } from '@/utils/safeArea';

const searchKeyword = ref('');
const hasSearched = ref(false);
const searchResults = ref([]);
const navBarHeight = ref(0);

const difficultyText = { 1: '初阶', 2: '中阶', 3: '高阶' };
const frequencyText = { 0: '不限', 1: '1练/周', 2: '2练/周', 3: '3练/周', 4: '4练/周', 5: '5练/周', 6: '6练/周', 7: '7练/周' };

let isMpWeixin = false;
// #ifdef MP-WEIXIN
isMpWeixin = true;
// #endif




onMounted(() => {
	if (isMpWeixin) {
		navBarHeight.value = getNavbarHeight();
	}
});

const handleSearch = async () => {
	const keyword = searchKeyword.value.trim();
	hasSearched.value = true;
	if (!keyword) {
		searchResults.value = [];
		return;
	}
	try {
		const res = await QueryPlanApi.searchPlansByName(keyword);
		if (res.code === 0) {
			searchResults.value = res.data.map(item => ({
				id: item.id,
				title: item.name,
				cover: item.urlCover,
				meta: `${difficultyText[item.difficultyLevel] || '初阶'} · ${frequencyText[item.frequencyPerWeek] || '1练/周'}`
			}));
		} else {
			uni.showToast({ title: res.msg || '搜索失败', icon: 'none' });
			searchResults.value = [];
		}
	} catch (err) {
		uni.showToast({ title: '网络异常,请重试', icon: 'none' });
		searchResults.value = [];
		console.error('搜索接口调用失败:', err);
	}
};

const handleCancel = () => {
	uni.navigateBack();
};

const goToDetail = (plan) => {
	if (!plan?.id) {
		uni.showToast({ title: '计划信息异常', icon: 'none' });
		return;
	}
	uni.navigateTo({
		url: `/pages4/pages/xunji/xunji-xunlian-jihua?planid=${plan.id}`,
	});
};
</script>

<style lang="scss" scoped>
.search-page {
	height: 100vh;
	background-color: #f5f5f5;
	display: flex;
	flex-direction: column;

	.search-header {
		padding: 14rpx 20rpx;
		background-color: #ffffff;
		box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
		z-index: 999;

		position: sticky;
		top: 0;


	}

	.search-results {
		flex: 1;
		padding: 30rpx 20rpx;
		box-sizing: border-box;

		.results-list {
			display: flex;
			flex-direction: column;

			.result-item {
				display: flex;
				background: #ffffff;
				border-radius: 16rpx;
				margin-bottom: 20rpx;
				overflow: hidden;
				padding: 20rpx;
				box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.05);

				.result-cover {
					width: 160rpx;
					height: 160rpx;
					border-radius: 12rpx;
					margin-right: 20rpx;
					flex-shrink: 0;
				}

				.result-info {
					flex: 1;
					display: flex;
					flex-direction: column;
					justify-content: center;

					.result-title {
						font-size: 28rpx;
						color: #333;
						font-weight: bold;
						line-height: 1.4;
						display: -webkit-box;
						-webkit-line-clamp: 2;
						-webkit-box-orient: vertical;
						overflow: hidden;
					}

					.result-meta {
						font-size: 24rpx;
						color: #999;
						margin-top: 10rpx;
					}
				}
			}
		}
	}
}
</style>