勿妄 1 week ago
commit d9d0dfb57d

@ -1,9 +1,17 @@
<script setup>
import { House, Cloudy, User, Cpu, Message, HomeFilled, MessageBox, Calendar } from '@element-plus/icons-vue'
import {useRoute} from 'vue-router'
import {useRoute,useRouter } from 'vue-router'
import { ref } from 'vue'
const route = useRoute();
const router = useRouter();
const searchText = ref('')
function goSearch() {
if (searchText.value.trim()) {
router.push({ path: '/search', query: { query: searchText.value.trim() } })
}
}
</script>
<template>
@ -31,6 +39,19 @@
<Cpu />
</el-icon>
</router-link>
</div>
<!-- 新增的搜索框 -->
<div class="header-search">
<input
type="text"
v-model="searchText"
@keyup.enter="goSearch"
placeholder="搜索..."
aria-label="搜索"
/>
<button @click="goSearch"></button>
</div>
<!-- 右侧部分 -->
@ -115,4 +136,41 @@
border-radius: 50%;
object-fit: cover;
}
.header-search {
display: flex;
align-items: center;
margin-left: 16px;
}
.header-search input {
width: 180px;
padding: 6px 10px;
font-size: 14px;
border-radius: 4px 0 0 4px;
border: 1px solid #ccc;
outline: none;
transition: border-color 0.2s;
}
.header-search input:focus {
border-color: #765ce6;
}
.header-search button {
padding: 6px 12px;
border: none;
background-color: #765ce6;
color: white;
font-weight: 600;
cursor: pointer;
border-radius: 0 4px 4px 0;
transition: background-color 0.2s;
user-select: none;
}
.header-search button:hover {
background-color: #5a42b8;
}
</style>

@ -1,6 +1,6 @@
<template>
<div class="left-nav">
<div class="nav-title">消息中心</div>
<div class="nav-title">消息中心</div>
<ul class="nav-list">
<li
v-for="(item, index) in navItems"
@ -22,10 +22,10 @@
const activeIndex = ref(0);
const navItems = [
{ text: '私信消息' },
{ text: '评论回复' },
{ text: '收到的赞' },
{ text: '系统通知' }
{ text: '通知消息' },
{ text: '系统通知' },
{ text: '用户消息' },
{ text: '系统消息' }
];
const handleNavClick = (index: number) => {

@ -9,6 +9,7 @@ import PostManager from '@/views/PostManagement.vue';
import Curriculum from '@/views/Curriculum.vue';
import DirectMessage from '@/views/DirectMessage.vue';
import AIManager from '@/views/AiManager.vue'
import SearchResult from "@/views/SearchResult.vue";
const routes: Array<RouteRecordRaw> = [
{
@ -84,7 +85,13 @@ const routes: Array<RouteRecordRaw> = [
path:'/directMessage',
name:'DirectMessage',
component:() => import('@/views/DirectMessage.vue'),
}
},
{
path: '/search',
name: 'SearchResult',
component: SearchResult,
},
];

@ -0,0 +1,395 @@
<template>
<div class="search-container">
<!-- 左侧栏 -->
<aside class="sidebar">
<section class="search-standards">
<ul>
<li
v-for="standard in standards"
:key="standard"
:class="{active: selectedStandard === standard}"
@click="selectStandard(standard)"
>{{ standard }}</li>
</ul>
</section>
<hr />
<section class="categories">
<h3>分类</h3>
<div class="category-group">
<div class="category-title">作业/资料</div>
<ul>
<li
v-for="college in colleges"
:key="college"
@click="selectCategory(college)"
:class="{active: selectedCategory === college}"
>
{{ college }}
</li>
<li>(以下省略)</li>
</ul>
</div>
<hr />
<div class="category-group">
<div class="category-title">帖子</div>
<ul>
<li
v-for="postType in postTypes"
:key="postType"
@click="selectCategory(postType)"
:class="{active: selectedCategory === postType}"
>
{{ postType }}
</li>
<li>(以下省略)</li>
</ul>
</div>
</section>
</aside>
<!-- 右侧栏 -->
<main class="search-results">
<div class="search-box">
<input
type="text"
v-model="searchQuery"
placeholder="请输入搜索关键字"
@keypress.enter="doSearch"
aria-label="搜索输入"
/>
<button @click="doSearch">🔍 </button>
</div>
<div class="results-list" v-if="pagedResults.length">
<div v-for="item in pagedResults" :key="item.id" class="result-item">
<div class="content">
<h4>{{ item.title }}</h4>
<p>{{ item.content }}</p>
</div>
<div class="preview-box">
<!-- 这里你可用图片或其它预览示例文本 -->
预览图/内容
</div>
</div>
</div>
<div v-else class="no-results">
暂无搜索结果
</div>
<div class="pagination" v-if="totalPages > 1">
<button @click="prevPage" :disabled="page === 1">上一页</button>
<span> {{ page }} / {{ totalPages }} </span>
<button @click="nextPage" :disabled="page === totalPages">下一页</button>
</div>
</main>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted } from 'vue'
import { useRoute } from 'vue-router'
//
const route = useRoute()
//
const standards = ['综合', '最新', '热度最高', '用户']
const selectedStandard = ref('综合')
//
const colleges = [
'计算机学院',
'遥感学院',
'电子信息学院',
// ...
]
const postTypes = [
'二手集市',
'吐槽树洞',
'校内组局',
// ...
]
const selectedCategory = ref<string | null>(null)
//
const searchQuery = ref('')
const results = ref([
// API
{ id: 1, title: '帖子标题1', content: '帖子内容A' },
{ id: 2, title: '帖子标题2', content: '帖子内容B' },
{ id: 3, title: '帖子标题3', content: '帖子内容C' },
{ id: 4, title: '帖子标题4', content: '帖子内容D' },
{ id: 5, title: '帖子标题5', content: '帖子内容E' },
{ id: 6, title: '帖子标题6', content: '帖子内容F' },
])
//
const page = ref(1)
const pageSize = 3
// queryquery
onMounted(() => {
const queryParam = route.query.query
if (typeof queryParam === 'string' && queryParam.trim()) {
searchQuery.value = queryParam.trim()
doSearch()
}
})
// selectedCategorysearchQuery
const filteredResults = computed(() => {
let filtered = results.value
// 1.
if (selectedCategory.value) {
filtered = filtered.filter(item => item.title.includes(selectedCategory.value!))
}
// 2. /content
if (searchQuery.value) {
const q = searchQuery.value.toLowerCase()
filtered = filtered.filter(item =>
item.title.toLowerCase().includes(q) || item.content.toLowerCase().includes(q)
)
}
// 3. TODO: selectedStandard
//
return filtered
})
const totalPages = computed(() => Math.max(1, Math.ceil(filteredResults.value.length / pageSize)))
const pagedResults = computed(() => {
const start = (page.value - 1) * pageSize
return filteredResults.value.slice(start, start + pageSize)
})
//
function selectStandard(std: string) {
selectedStandard.value = std
page.value = 1
doSearch()
}
function selectCategory(cat: string) {
selectedCategory.value = cat
page.value = 1
doSearch()
}
function doSearch() {
page.value = 1
//
}
function prevPage() {
if (page.value > 1) page.value--
}
function nextPage() {
if (page.value < totalPages.value) page.value++
}
</script>
<style scoped>
.search-container {
width: 1800px;
height: 1000px;
margin: 20px auto;
display: flex;
gap: 24px;
padding: 24px;
background: linear-gradient(90deg, #f6e7f7, #e2e0f9);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 24px;
box-sizing: border-box;
}
/* 左侧栏 */
.sidebar {
flex: 0 0 280px;
background: #fff;
padding: 24px;
border-radius: 8px;
box-shadow: 0 0 12px #ddd;
display: flex;
flex-direction: column;
gap: 16px;
}
.sidebar ul {
list-style: none;
padding: 0;
margin: 0;
}
.sidebar ul li {
margin: 10px 0;
cursor: pointer;
user-select: none;
transition: color 0.2s;
font-size: 1.1em;
}
.sidebar ul li:hover {
color: #7a42f4;
}
.sidebar ul li.active {
font-weight: 700;
color: #581ce0;
}
.categories h3 {
margin-bottom: 12px;
font-size: 1.3em;
font-weight: 700;
}
.category-group {
margin-bottom: 16px;
}
.category-title {
font-weight: 600;
margin-bottom: 8px;
font-size: 1.1em;
}
/* 右侧栏 */
.search-results {
flex: 1;
background: #faf8ff;
padding: 32px;
border-radius: 8px;
box-shadow: 0 0 12px #ccc;
display: flex;
flex-direction: column;
gap: 24px;
overflow: hidden;
}
.search-box {
display: flex;
gap: 12px;
align-items: center;
}
.search-box input {
flex: 1;
padding: 12px 16px;
font-size: 1.2em;
border: 1px solid #ccc;
border-radius: 6px;
outline: none;
transition: border-color 0.2s;
}
.search-box input:focus {
border-color: #765ce6;
}
.search-box button {
cursor: pointer;
padding: 10px 18px;
font-size: 1.1em;
border: none;
background-color: #765ce6;
color: white;
border-radius: 6px;
user-select: none;
transition: background-color 0.2s;
}
.search-box button:hover {
background-color: #5a42b8;
}
.results-list {
flex-grow: 1;
display: flex;
flex-direction: column;
gap: 16px;
overflow-y: auto;
}
.result-item {
display: flex;
justify-content: space-between;
padding: 16px;
background: white;
border: 1px solid #ccc;
border-radius: 8px;
box-sizing: border-box;
}
.content {
flex: 1;
margin-right: 16px;
line-height: 1.5em;
}
.content h4 {
margin: 0 0 8px 0;
font-weight: 600;
font-size: 1.3em;
}
.preview-box {
width: 150px;
background: #ccc;
color: #444;
display: flex;
justify-content: center;
align-items: center;
border-radius: 6px;
user-select: none;
font-size: 1em;
}
.no-results {
font-size: 1.2em;
color: #999;
margin-top: 30px;
text-align: center;
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
}
.pagination {
display: flex;
justify-content: center;
align-items: center;
gap: 24px;
}
.pagination button {
cursor: pointer;
border: none;
background: #765ce6;
color: white;
padding: 10px 18px;
border-radius: 6px;
user-select: none;
font-size: 1.1em;
transition: background-color 0.2s;
}
.pagination button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.pagination button:hover:not(:disabled) {
background-color: #5a42b8;
}
</style>
Loading…
Cancel
Save