feat: 增强课程搜索功能,添加分类筛选
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
yuliang_guo
2026-01-30 16:27:34 +08:00
parent 920c6a64c8
commit b2e1ed02d1

View File

@@ -252,17 +252,6 @@
<div class="course-config-panel"> <div class="course-config-panel">
<div class="panel-header"> <div class="panel-header">
<h3>课程配置</h3> <h3>课程配置</h3>
<el-input
v-model="courseSearch"
placeholder="搜索课程"
clearable
style="width: 200px"
@input="handleCourseSearch"
>
<template #prefix>
<el-icon><Search /></el-icon>
</template>
</el-input>
</div> </div>
<!-- 课程库 --> <!-- 课程库 -->
@@ -271,6 +260,33 @@
<span>可选课程</span> <span>可选课程</span>
<el-tag size="small">{{ filteredCourses.length }} </el-tag> <el-tag size="small">{{ filteredCourses.length }} </el-tag>
</div> </div>
<!-- 搜索和筛选 -->
<div class="course-filter">
<el-input
v-model="courseSearch"
placeholder="搜索课程名称..."
clearable
size="small"
>
<template #prefix>
<el-icon><Search /></el-icon>
</template>
</el-input>
<el-select
v-model="courseCategory"
placeholder="分类筛选"
clearable
size="small"
style="width: 120px"
>
<el-option
v-for="cat in courseCategories"
:key="cat"
:label="cat"
:value="cat"
/>
</el-select>
</div>
<div class="library-content" v-loading="coursesLoading"> <div class="library-content" v-loading="coursesLoading">
<div <div
v-for="course in filteredCourses" v-for="course in filteredCourses"
@@ -463,6 +479,7 @@ const filters = ref<{
// 编辑状态 // 编辑状态
const editingPath = ref<EditingPath | null>(null) const editingPath = ref<EditingPath | null>(null)
const courseSearch = ref('') const courseSearch = ref('')
const courseCategory = ref('')
const isDragging = ref(false) const isDragging = ref(false)
const isDraggingOver = ref(false) const isDraggingOver = ref(false)
@@ -471,13 +488,33 @@ const positions = ref<Position[]>([])
const courses = ref<Course[]>([]) const courses = ref<Course[]>([])
// ========== 计算属性 ========== // ========== 计算属性 ==========
// 获取所有课程分类
const courseCategories = computed(() => {
const categories = new Set<string>()
courses.value.forEach(c => {
if (c.category) categories.add(c.category)
})
return Array.from(categories).sort()
})
const filteredCourses = computed(() => { const filteredCourses = computed(() => {
if (!courseSearch.value) return courses.value let result = courses.value
// 按分类筛选
if (courseCategory.value) {
result = result.filter(c => c.category === courseCategory.value)
}
// 按关键词搜索
if (courseSearch.value) {
const keyword = courseSearch.value.toLowerCase() const keyword = courseSearch.value.toLowerCase()
return courses.value.filter(c => result = result.filter(c =>
(c.name || c.title || '').toLowerCase().includes(keyword) || (c.name || c.title || '').toLowerCase().includes(keyword) ||
(c.category || '').toLowerCase().includes(keyword) (c.category || '').toLowerCase().includes(keyword)
) )
}
return result
}) })
const requiredCount = computed(() => { const requiredCount = computed(() => {
@@ -1083,6 +1120,18 @@ onMounted(() => {
font-weight: 500; font-weight: 500;
} }
.course-filter {
display: flex;
gap: 8px;
padding: 12px 16px;
background: #f5f7fa;
border-bottom: 1px solid #ebeef5;
.el-input {
flex: 1;
}
}
.library-content, .library-content,
.selected-content { .selected-content {
flex: 1; flex: 1;