158 lines
4.0 KiB
Vue
158 lines
4.0 KiB
Vue
|
<template>
|
|||
|
<div class="search-result-view">
|
|||
|
<header class="top-bar">
|
|||
|
<button class="back-btn" @click="goBack"><</button>
|
|||
|
<div class="search-input-wrapper">
|
|||
|
<span class="search-icon">🔍</span>
|
|||
|
<input type="text" v-model="searchQuery" @keyup.enter="performSearch" />
|
|||
|
</div>
|
|||
|
</header>
|
|||
|
|
|||
|
<div class="tabs">
|
|||
|
<button :class="{ active: activeTab === 'all' }" @click="activeTab = 'all'">全部</button>
|
|||
|
<button :class="{ active: activeTab === 'product' }" @click="activeTab = 'product'">产品</button>
|
|||
|
<button :class="{ active: activeTab === 'article' }" @click="activeTab = 'article'">文章</button>
|
|||
|
<button :class="{ active: activeTab === 'ingredient' }" @click="activeTab = 'ingredient'">成分</button>
|
|||
|
</div>
|
|||
|
|
|||
|
<main class="results-list">
|
|||
|
<!-- Product Results -->
|
|||
|
<div v-if="activeTab === 'all' || activeTab === 'product'" class="result-item" @click="goToResult('product1')">
|
|||
|
<h4>[某品牌纯牛奶]</h4>
|
|||
|
<p>安全评级: <span class="score-a">A</span> | 营养评级: <span class="score-high">高</span></p>
|
|||
|
</div>
|
|||
|
<div v-if="activeTab === 'all' || activeTab === 'product'" class="result-item" @click="goToResult('product2')">
|
|||
|
<h4>[某品牌儿童牛奶]</h4>
|
|||
|
<p>安全评级: <span class="score-c">C</span> | 营养评级: <span class="score-mid">中</span></p>
|
|||
|
</div>
|
|||
|
|
|||
|
<!-- Article Results -->
|
|||
|
<div v-if="activeTab === 'all' || activeTab === 'article'" class="result-item">
|
|||
|
<h4>牛奶过敏的宝宝应该怎么办?</h4>
|
|||
|
<p class="article-summary">本文将详细介绍牛奶过敏的症状、原因以及应对方法...</p>
|
|||
|
</div>
|
|||
|
</main>
|
|||
|
</div>
|
|||
|
</template>
|
|||
|
|
|||
|
<script setup lang="ts">
|
|||
|
import { ref, onMounted } from 'vue';
|
|||
|
import { useRoute, useRouter } from 'vue-router';
|
|||
|
|
|||
|
const route = useRoute();
|
|||
|
const router = useRouter();
|
|||
|
const searchQuery = ref('');
|
|||
|
const activeTab = ref('all');
|
|||
|
|
|||
|
onMounted(() => {
|
|||
|
searchQuery.value = (route.query.q as string) || '';
|
|||
|
});
|
|||
|
|
|||
|
const goBack = () => {
|
|||
|
router.back();
|
|||
|
};
|
|||
|
|
|||
|
const performSearch = () => {
|
|||
|
// In a real app, this would re-trigger the search
|
|||
|
console.log('Searching for:', searchQuery.value);
|
|||
|
};
|
|||
|
|
|||
|
const goToResult = (id: string) => {
|
|||
|
router.push({ name: 'result', params: { id } });
|
|||
|
};
|
|||
|
</script>
|
|||
|
|
|||
|
<style scoped>
|
|||
|
.search-result-view {
|
|||
|
padding-top: 110px; /* Space for top-bar and tabs */
|
|||
|
}
|
|||
|
.top-bar {
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
padding: 10px 15px;
|
|||
|
background-color: #fff;
|
|||
|
border-bottom: 1px solid #e5e7eb;
|
|||
|
position: fixed;
|
|||
|
top: 0;
|
|||
|
left: 0;
|
|||
|
right: 0;
|
|||
|
max-width: 428px;
|
|||
|
margin: 0 auto;
|
|||
|
z-index: 10;
|
|||
|
}
|
|||
|
.back-btn {
|
|||
|
background: none; border: none; font-size: 20px; cursor: pointer; padding-right: 10px;
|
|||
|
}
|
|||
|
.search-input-wrapper {
|
|||
|
flex-grow: 1;
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
background-color: #f3f4f6;
|
|||
|
border-radius: 18px;
|
|||
|
padding: 8px 12px;
|
|||
|
}
|
|||
|
.search-icon {
|
|||
|
margin-right: 8px;
|
|||
|
}
|
|||
|
.search-input-wrapper input {
|
|||
|
border: none;
|
|||
|
outline: none;
|
|||
|
background: transparent;
|
|||
|
width: 100%;
|
|||
|
}
|
|||
|
|
|||
|
.tabs {
|
|||
|
display: flex;
|
|||
|
justify-content: space-around;
|
|||
|
padding: 10px 0;
|
|||
|
background-color: #fff;
|
|||
|
border-bottom: 1px solid #e5e7eb;
|
|||
|
position: fixed;
|
|||
|
top: 57px; /* Position below top-bar */
|
|||
|
left: 0;
|
|||
|
right: 0;
|
|||
|
max-width: 428px;
|
|||
|
margin: 0 auto;
|
|||
|
z-index: 9;
|
|||
|
}
|
|||
|
.tabs button {
|
|||
|
background: none;
|
|||
|
border: none;
|
|||
|
font-size: 16px;
|
|||
|
color: #6b7280;
|
|||
|
cursor: pointer;
|
|||
|
padding-bottom: 5px;
|
|||
|
border-bottom: 2px solid transparent;
|
|||
|
}
|
|||
|
.tabs button.active {
|
|||
|
color: #22c55e;
|
|||
|
border-bottom-color: #22c55e;
|
|||
|
}
|
|||
|
|
|||
|
.results-list {
|
|||
|
padding: 0 20px;
|
|||
|
}
|
|||
|
.result-item {
|
|||
|
padding: 15px 0;
|
|||
|
border-bottom: 1px solid #e5e7eb;
|
|||
|
cursor: pointer;
|
|||
|
}
|
|||
|
.result-item h4 {
|
|||
|
font-size: 16px;
|
|||
|
margin-bottom: 5px;
|
|||
|
}
|
|||
|
.result-item p {
|
|||
|
font-size: 14px;
|
|||
|
color: #6b7280;
|
|||
|
}
|
|||
|
.article-summary {
|
|||
|
display: -webkit-box;
|
|||
|
-webkit-line-clamp: 2;
|
|||
|
-webkit-box-orient: vertical;
|
|||
|
overflow: hidden;
|
|||
|
}
|
|||
|
.score-a { color: #22c55e; font-weight: bold; }
|
|||
|
.score-c { color: orange; font-weight: bold; }
|
|||
|
.score-high { color: #22c55e; }
|
|||
|
.score-mid { color: orange; }
|
|||
|
</style>
|