feat: 重写搜索栏组件,添加标签页筛选功能

This commit is contained in:
wkc
2026-02-27 14:05:05 +08:00
parent b03c9c4efe
commit 0554cb5df1

View File

@@ -1,62 +1,25 @@
<template> <template>
<div class="search-bar-container"> <div class="search-filter-bar">
<el-card class="search-card" shadow="hover">
<el-row :gutter="12" align="middle">
<el-col :span="8">
<el-input <el-input
v-model="searchKeyword" v-model="searchKeyword"
placeholder="请输入项目名称" placeholder="请输入关键词搜索项目"
prefix-icon="el-icon-search" prefix-icon="el-icon-search"
clearable clearable
size="medium" size="small"
class="search-input"
@keyup.enter.native="handleSearch" @keyup.enter.native="handleSearch"
@clear="handleSearch"
/> />
</el-col> <div class="tab-filters">
<el-col :span="5"> <div
<el-select v-for="tab in tabs"
v-model="selectedStatus" :key="tab.value"
placeholder="项目状态" :class="['tab-item', { active: activeTab === tab.value }]"
clearable @click="handleTabChange(tab.value)"
size="medium"
style="width: 100%"
@change="handleStatusChange"
> >
<el-option {{ tab.label }}({{ tab.count }})
v-for="item in statusOptions" </div>
:key="item.value" </div>
:label="item.label"
:value="item.value"
/>
</el-select>
</el-col>
<el-col :span="4">
<el-button
type="primary"
icon="el-icon-search"
size="medium"
@click="handleSearch"
>搜索</el-button>
<el-button
icon="el-icon-refresh"
size="medium"
@click="handleReset"
>重置</el-button>
</el-col>
<el-col :span="7" style="text-align: right">
<el-button
type="primary"
icon="el-icon-plus"
size="medium"
@click="handleAdd"
>新建项目</el-button>
<el-button
icon="el-icon-folder-opened"
size="medium"
@click="handleImport"
>导入历史项目</el-button>
</el-col>
</el-row>
</el-card>
</div> </div>
</template> </template>
@@ -67,74 +30,101 @@ export default {
showSearch: { showSearch: {
type: Boolean, type: Boolean,
default: true default: true
},
tabCounts: {
type: Object,
default: () => ({
all: 0,
ongoing: 0,
completed: 0,
archived: 0
})
} }
}, },
data() { data() {
return { return {
searchKeyword: '', searchKeyword: '',
selectedStatus: '', activeTab: 'all',
statusOptions: [ tabs: [
{ label: '进行中', value: '0' }, { label: '全部项目', value: 'all', count: 0 },
{ label: '已完成', value: '1' }, { label: '进行中', value: 'ongoing', count: 0 },
{ label: '已归档', value: '2' } { label: '已完成', value: 'completed', count: 0 },
{ label: '已归档', value: 'archived', count: 0 }
] ]
} }
}, },
watch: {
tabCounts: {
handler(newVal) {
this.tabs = this.tabs.map(tab => ({
...tab,
count: newVal[tab.value] || 0
}))
},
immediate: true,
deep: true
}
},
methods: { methods: {
/** 搜索 */ /** 搜索 */
handleSearch() { handleSearch() {
this.emitQuery() this.emitQuery()
}, },
/** 状态变化 */ /** 标签页切换 */
handleStatusChange() { handleTabChange(tabValue) {
this.emitQuery() this.activeTab = tabValue
},
/** 重置 */
handleReset() {
this.searchKeyword = ''
this.selectedStatus = ''
this.emitQuery() this.emitQuery()
}, },
/** 发送查询 */ /** 发送查询 */
emitQuery() { emitQuery() {
this.$emit('query', { this.$emit('query', {
projectName: this.searchKeyword || null, projectName: this.searchKeyword || null,
status: this.selectedStatus || null status: this.activeTab === 'all' ? null : this.activeTab
}) })
},
/** 新增 */
handleAdd() {
this.$emit('add')
},
/** 导入 */
handleImport() {
this.$emit('import')
} }
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.search-bar-container { .search-filter-bar {
margin-bottom: 12px; display: flex;
align-items: center;
gap: 24px;
padding: 16px 20px;
background: #ffffff;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
} }
.search-card { .search-input {
border-radius: 4px; width: 240px;
border: 1px solid #EBEEF5; height: 40px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08); }
:deep(.el-card__body) { .tab-filters {
padding: 12px 16px; display: flex;
align-items: center;
gap: 24px;
}
.tab-item {
font-size: 14px;
color: #6B7280;
cursor: pointer;
padding: 6px 12px;
border-radius: 6px;
transition: all 0.2s ease;
user-select: none;
&:hover {
color: #3B82F6;
} }
}
:deep(.el-button--medium) { &.active {
padding: 10px 16px; color: #3B82F6;
margin-left: 8px; background: #EFF6FF;
font-weight: 500;
&:first-child {
margin-left: 0;
} }
} }
</style> </style>