jihua-search.vue 5.91 KB
<!-- 
基础版训练计划搜索页(仅关键词搜索)
页面位于:训记横向导航栏的‘计划’模块,右侧搜索图标点击后进入的页面就是,核心功能是提供一个简单的搜索界面,允许用户输入关键词搜索训练计划,还未完成 
-->
<template>
	<view class="search-page">
		<!-- 顶部搜索栏 -->
		<view class="search-header">
			<view class="search-input-wrapper">
				<uni-icons type="search" size="18" color="#999" class="search-icon"></uni-icons>
				<input ref="searchInput" v-model="searchKeyword" class="search-input" type="text" placeholder="搜索训练计划"
					placeholder-style="color:#999" confirm-type="search" @confirm="handleSearch" focus />
			</view>
			<view class="cancel-btn" @click="handleCancel">
				<text class="cancel-text">取消</text>
			</view>
		</view>

		<!-- 搜索结果区域 -->
		<view class="search-results">
			<!-- 未搜索时提示 -->
			<view v-if="!hasSearched" class="empty-hint">
				<text>请输入关键词搜索训练计划</text>
			</view>

			<!-- 已搜索但无结果 -->
			<view v-else-if="searchResults.length === 0" class="empty-hint">
				<text>未找到相关训练计划</text>
			</view>

			<!-- 搜索结果列表 -->
			<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>
		</view>
	</view>
</template>

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

// 响应式数据
const searchKeyword = ref('');
const hasSearched = ref(false);
const searchResults = ref([]);
const allPlans = ref([]);
const searchInput = ref(null);
// 难度/频率/场景/人群 数字转文字映射(和列表页保持一致)
const difficultyText = { 1: '初阶', 2: '中阶', 3: '高阶' };
const frequencyText = { 0: '不限', 1: '1练/周', 2: '2练/周', 3: '3练/周', 4: '4练/周', 5: '5练/周', 6: '6练/周', 7: '7练/周' };
// 页面加载时获取全局数据
onMounted(() => {
	// 自动聚焦输入框(uni-app 需要延迟)
	setTimeout(() => {
		if (searchInput.value && typeof searchInput.value.focus === 'function') {
			searchInput.value.focus();
		}
	}, 300);
});
// 返回
const goBack = () => {
	uni.navigateBack();
};
// 执行接口搜索
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, // 接口字段name → 页面字段title
				cover: item.urlCover, // 接口字段urlCover → 页面字段cover
				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 {
	// 整个页面往下偏移,避免被顶部导航栏遮挡
	padding-top: 160rpx;
	height: 100vh;
	background-color: #f5f5f5;
	display: flex;
	flex-direction: column;
}

/* 顶部搜索栏 */
.search-header {
	display: flex;
	align-items: center;
	padding: 20rpx 20rpx 20rpx 30rpx;
	background-color: #ffffff;
	// box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
	z-index: 999;
	// 固定顶部搜索栏
	position: fixed;
	top: 160rpx;
	left: 0;
	right: 0;
}

.search-input-wrapper {
	flex: 1;
	background-color: #f5f5f5;
	border-radius: 12rpx;
	padding: 0 20rpx;
	height: 64rpx;
	display: flex;
	align-items: center;
	gap: 10rpx;
}

.search-icon {
	flex-shrink: 0;
}

.search-input {
	flex: 1;
	height: 100%;
	font-size: 28rpx;
	color: #333;
	background: transparent;
	border: none;
}

.cancel-btn {
	margin-left: 24rpx;
	padding: 10rpx 0;
	height: 64rpx;
	display: flex;
	align-items: center;
}

.cancel-text {
	font-size: 28rpx;
	color: #333;
	/* 主题绿色,与你的 UI 一致 */
}

/* 搜索结果区域 */
.search-results {
	margin-top: 100rpx; // 改成 100rpx,避免被搜索栏遮挡
	flex: 1;
	padding: 30rpx 20rpx;
	overflow-y: auto;
}

.empty-hint {
	text-align: center;
	color: #999;
	font-size: 28rpx;
	margin-top: 200rpx;
}

.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>