Преглед на файлове

1、课程筛选优化树级菜单可搜索
2、blockly课程筛选优化树级菜单可搜索

liyanbo преди 5 месеца
родител
ревизия
cb9054f0f8
променени са 2 файла, в които са добавени 624 реда и са изтрити 429 реда
  1. 305 233
      src/views/bjdx/course/index.vue
  2. 319 196
      src/views/blockly/blockly/index.vue

+ 305 - 233
src/views/bjdx/course/index.vue

@@ -1,234 +1,227 @@
 <template>
-  <ContentWrap>
-    <!-- 搜索工作栏 -->
-    <el-form
-      class="-mb-15px"
-      :model="queryParams"
-      ref="queryFormRef"
-      :inline="true"
-      label-width="90px"
-    >
-      <el-form-item label="课程类型">
-        <el-select
-          v-model="queryParams.ctTypeNode"
-          placeholder="请选择课程类型"
-          class="!w-240px"
-          @change="handleCtTypeNodeChange"
-        >
-          <el-option label="ai通识课" value="1" />
-          <el-option label="ai实操课" value="2" />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="大纲课程" prop="courseType">
-        <el-tree-select
+  <el-row :gutter="20">
+    <!-- 左侧课程类型树 -->
+    <el-col :span="5" :xs="24">
+      <ContentWrap class="h-1/1" style="overflow-x: auto; overflow-y: auto; height: calc(100vh - 100px);" >
+        <!-- 课程类型切换 -->
+        <div class="mb-20px">
+          <el-form-item label="课程类型" class="!mb-0">
+            <el-select
+              v-model="queryParams.ctTypeNode"
+              placeholder="请选择课程类型"
+              class="!w-full"
+              @change="handleCtTypeNodeChange"
+            >
+              <el-option label="ai通识课" value="1" />
+              <el-option label="ai实操课" value="2" />
+            </el-select>
+          </el-form-item>
+        </div>
+        <!-- 搜索框 -->
+        <div class="mb-20px">
+          <el-input
+            v-model="treeSearchValue"
+            placeholder="搜索课程类型"
+            clearable
+            @input="handleTreeSearch"
+            class="!w-full"
+            prefix-icon="ep:search"
+          />
+        </div>
+        <!-- 课程类型树形选择器 -->
+        <el-tree
           v-model="queryParams.courseType"
-          :data="courseTypeTree"
-          :props="{...defaultProps,
+          :data="filteredCourseTypeTree"
+          :props="{
             label: (node) => `${node.ctTypeNode === '0' || node.ctTypeNode === undefined ? node.ctType : node.ctTypeSort + '、' + node.ctType}`,
-            }"
-          placeholder="请选择课程类型"
+            children: 'children',
+            value: 'id'
+          }"
           :default-expand-all="true"
-          class="!w-240px"
-          @change="handleQuery"
+          node-key="id"
+          highlight-current
+          @node-click="handleCourseTypeClick"
         />
-      </el-form-item>
-      <el-form-item label="内容类型" prop="courseContentType">
-        <el-select
-          v-model="queryParams.courseContentType"
-          placeholder="请选择内容类型"
-          clearable
-          class="!w-240px"
-          @change="handleQuery"
+      </ContentWrap>
+    </el-col>
+    <el-col :span="19" :xs="24">
+      <!-- 搜索工作栏 -->
+      <ContentWrap>
+        <el-form
+          class="-mb-15px"
+          :model="queryParams"
+          ref="queryFormRef"
+          :inline="true"
+          label-width="90px"
         >
-          <el-option
-            v-for="dict in getStrDictOptions(DICT_TYPE.COURSE_COUTNET_TYPE)"
-            :key="dict.value"
-            :label="dict.label"
-            :value="dict.value"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="课程名称" prop="courseName">
-        <el-input
-          v-model="queryParams.courseName"
-          placeholder="请输入课程名称"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-<!--      <el-form-item label="课程作者" prop="courseAuthor">
-        <el-input
-          v-model="queryParams.courseAuthor"
-          placeholder="请输入课程作者"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="课程老师" prop="courseTeacher">
-        <el-input
-          v-model="queryParams.courseTeacher"
-          placeholder="请输入课程老师"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
+          <el-form-item label="内容类型" prop="courseContentType">
+            <el-select
+              v-model="queryParams.courseContentType"
+              placeholder="请选择内容类型"
+              clearable
+              class="!w-240px"
+              @change="handleQuery"
+            >
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.COURSE_COUTNET_TYPE)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="课程名称" prop="courseName">
+            <el-input
+              v-model="queryParams.courseName"
+              placeholder="请输入课程名称"
+              clearable
+              @keyup.enter="handleQuery"
+              class="!w-240px"
+            />
+          </el-form-item>
+          <el-form-item label="是否有检查" prop="courseIsInspect">
+            <el-select
+              v-model="queryParams.courseIsInspect"
+              placeholder="请选择是否有检查"
+              clearable
+              class="!w-240px"
+              @change="handleQuery"
+            >
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="课程标签" prop="courseLabel">
+            <el-select
+              v-model="queryParams.courseLabel"
+              placeholder="请选择课程标签"
+              clearable
+              class="!w-240px"
+              @change="handleQuery"
+            >
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.COURSE_LABEL)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="课程状态" prop="courseStatus">
+            <el-select
+              v-model="queryParams.courseStatus"
+              placeholder="请选择课程状态"
+              clearable
+              class="!w-240px"
+              @change="handleQuery"
+            >
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.COMMON_STATUS)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+            <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+            <el-button
+              type="primary"
+              plain
+              @click="openForm('create')"
+              v-hasPermi="['bjdx:course:create']"
+            >
+              <Icon icon="ep:plus" class="mr-5px" /> 新增
+            </el-button>
+            <el-button
+              type="success"
+              plain
+              @click="handleExport"
+              :loading="exportLoading"
+              v-hasPermi="['bjdx:course:export']"
+            >
+              <Icon icon="ep:download" class="mr-5px" /> 导出
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </ContentWrap>
+
+      <!-- 列表 -->
+      <ContentWrap>
+        <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+          <el-table-column label="课程类型" align="center" prop="courseTypeName" />
+          <el-table-column label="课程名称" align="center" prop="courseName" />
+          <el-table-column label="内容类型" align="center" prop="courseContentType" >
+            <template #default="scope">
+              <dict-tag :type="DICT_TYPE.COURSE_COUTNET_TYPE" :value="scope.row.courseContentType" />
+            </template>
+          </el-table-column>
+          <el-table-column label="课程内容" align="center" prop="courseContent" width="120px">
+            【预览查看】
+          </el-table-column>
+          <el-table-column label="是否有检查" align="center" prop="courseIsInspect">
+            <template #default="scope">
+              <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.courseIsInspect" />
+            </template>
+          </el-table-column>
+          <el-table-column label="课程标签" align="center" prop="courseLabel">
+            <template #default="scope">
+              <dict-tag :type="DICT_TYPE.COURSE_LABEL" :value="scope.row.courseLabel" />
+            </template>
+          </el-table-column>
+          <el-table-column label="课程排序" align="center" prop="courseOrder"/>
+          <el-table-column label="课程状态" align="center" prop="courseStatus">
+            <template #default="scope">
+              <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.courseStatus" />
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" align="center" min-width="180px">
+            <template #default="scope">
+              <el-button
+                link
+                type="primary"
+                v-if="scope.row.tenantId == getTenantId()"
+                @click="openForm('update', scope.row.id)"
+                v-hasPermi="['bjdx:course:update']"
+              >
+                编辑
+              </el-button>
+              <el-button
+                link
+                type="success"
+                :disabled="scope.row.courseContentType !== 'video'"
+                title="仅视频课程可配置"
+                @click="handleConfig(scope.row.id,scope.row.courseName,scope.row.tenantId)"
+              >
+                配置
+              </el-button>
+              <el-button
+                link
+                type="danger"
+                v-if="scope.row.tenantId == getTenantId()"
+                @click="handleDelete(scope.row.id)"
+                v-hasPermi="['bjdx:course:delete']"
+              >
+                删除
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <!-- 分页 -->
+        <Pagination
+          :total="total"
+          v-model:page="queryParams.pageNo"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
         />
-      </el-form-item>-->
-      <el-form-item label="是否有检查" prop="courseIsInspect">
-        <el-select
-          v-model="queryParams.courseIsInspect"
-          placeholder="请选择是否有检查"
-          clearable
-          class="!w-240px"
-          @change="handleQuery"
-        >
-          <el-option
-            v-for="dict in getStrDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
-            :key="dict.value"
-            :label="dict.label"
-            :value="dict.value"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="课程标签" prop="courseLabel">
-        <el-select
-          v-model="queryParams.courseLabel"
-          placeholder="请选择课程标签"
-          clearable
-          class="!w-240px"
-          @change="handleQuery"
-        >
-          <el-option
-            v-for="dict in getStrDictOptions(DICT_TYPE.COURSE_LABEL)"
-            :key="dict.value"
-            :label="dict.label"
-            :value="dict.value"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="课程状态" prop="courseStatus">
-        <el-select
-          v-model="queryParams.courseStatus"
-          placeholder="请选择课程状态"
-          clearable
-          class="!w-240px"
-          @change="handleQuery"
-        >
-          <el-option
-            v-for="dict in getStrDictOptions(DICT_TYPE.COMMON_STATUS)"
-            :key="dict.value"
-            :label="dict.label"
-            :value="dict.value"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item>
-        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
-        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
-        <el-button
-          type="primary"
-          plain
-          @click="openForm('create')"
-          v-hasPermi="['bjdx:course:create']"
-        >
-          <Icon icon="ep:plus" class="mr-5px" /> 新增
-        </el-button>
-        <el-button
-          type="success"
-          plain
-          @click="handleExport"
-          :loading="exportLoading"
-          v-hasPermi="['bjdx:course:export']"
-        >
-          <Icon icon="ep:download" class="mr-5px" /> 导出
-        </el-button>
-      </el-form-item>
-    </el-form>
-  </ContentWrap>
-
-  <!-- 列表 -->
-  <ContentWrap>
-    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
-<!--      <el-table-column label="课程d" align="center" prop="id" />-->
-      <el-table-column label="课程类型" align="center" prop="courseTypeName" />
-      <el-table-column label="课程名称" align="center" prop="courseName" />
-      <el-table-column label="内容类型" align="center" prop="courseContentType" >
-        <template #default="scope">
-          <dict-tag :type="DICT_TYPE.COURSE_COUTNET_TYPE" :value="scope.row.courseContentType" />
-        </template>
-      </el-table-column>
-<!--      <el-table-column label="课程路径" align="center" prop="courseVideoPath" />-->
-      <el-table-column label="课程内容" align="center" prop="courseContent" width="120px">
-          【预览查看】
-      </el-table-column>
-<!--      <el-table-column label="课程作者" align="center" prop="courseAuthor" />-->
-<!--      <el-table-column label="课程老师" align="center" prop="courseTeacher" />-->
-<!--      <el-table-column label="课程大小" align="center" prop="courseSize" />-->
-<!--      <el-table-column label="课程时长" align="center" prop="courseTime" />-->
-      <el-table-column label="是否有检查" align="center" prop="courseIsInspect">
-        <template #default="scope">
-          <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.courseIsInspect" />
-        </template>
-      </el-table-column>
-      <el-table-column label="课程标签" align="center" prop="courseLabel">
-        <template #default="scope">
-          <dict-tag :type="DICT_TYPE.COURSE_LABEL" :value="scope.row.courseLabel" />
-        </template>
-      </el-table-column>
-      <el-table-column label="课程排序" align="center" prop="courseOrder"/>
-      <el-table-column label="课程状态" align="center" prop="courseStatus">
-        <template #default="scope">
-          <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.courseStatus" />
-        </template>
-      </el-table-column>
-      <el-table-column label="操作" align="center" min-width="180px"> <!-- 调整列宽适配新按钮 -->
-        <template #default="scope">
-          <el-button
-            link
-            type="primary"
-            v-if="scope.row.tenantId == getTenantId()"
-            @click="openForm('update', scope.row.id)"
-            v-hasPermi="['bjdx:course:update']"
-          >
-            编辑
-          </el-button>
-<!--          <el-button-->
-<!--            link-->
-<!--            type="info"-->
-<!--            @click="openPreview(scope.row)"-->
-<!--          >-->
-<!--            预览-->
-<!--          </el-button>-->
-          <el-button
-            link
-            type="success"
-            :disabled="scope.row.courseContentType !== 'video'"
-            title="仅视频课程可配置"
-            @click="handleConfig(scope.row.id,scope.row.courseName,scope.row.tenantId)"
-          >
-            配置
-          </el-button>
-          <el-button
-            link
-            type="danger"
-            v-if="scope.row.tenantId == getTenantId()"
-            @click="handleDelete(scope.row.id)"
-            v-hasPermi="['bjdx:course:delete']"
-          >
-            删除
-          </el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-    <!-- 分页 -->
-    <Pagination
-      :total="total"
-      v-model:page="queryParams.pageNo"
-      v-model:limit="queryParams.pageSize"
-      @pagination="getList"
-    />
-  </ContentWrap>
+      </ContentWrap>
+    </el-col>
+  </el-row>
 
   <!-- 表单弹窗:添加/修改 -->
   <CourseForm ref="formRef" @success="getList" />
@@ -244,10 +237,9 @@ import { CourseApi, CourseVO } from '@/api/bjdx/course'
 import CourseForm from './CourseForm.vue'
 import CoursePreview from '@/views/bjdx/course/CoursePreview.vue'
 import { useRouter } from 'vue-router'
-import { defaultProps, handleTree } from '@/utils/tree'
+import { handleTree } from '@/utils/tree'
 import { CourseTypeApi } from '@/api/bjdx/coursetype'
 import { getTenantId } from '@/utils/auth'
-import { ElButton } from 'element-plus'
 
 /** 课程 列表 */
 defineOptions({ name: 'Course' })
@@ -283,11 +275,12 @@ const exportLoading = ref(false) // 导出的加载中
 // 新增预览相关变量
 const previewRef = ref()
 const courseTypeTree = ref() // 树形结构
+const treeSearchValue = ref('') // 树形搜索值
 
 /** 打开预览弹窗 */
 const openPreview = (row) => {
   // 使用$nextTick确保组件挂载后调用
-    previewRef.value?.open(row)
+  previewRef.value?.open(row)
 }
 
 /** 查询列表 */
@@ -311,15 +304,66 @@ const handleQuery = async () => {
 /** 处理课程类型节点变更 */
 const handleCtTypeNodeChange = (ctTypeNode) => {
   queryParams.courseType = undefined
-  getCourseTypeTree(ctTypeNode)
+  treeSearchValue.value = '' // 清空搜索框
+  getCourseTypeTree(ctTypeNode).then(() => {
+    // 选择课程类型后自动搜索
+    handleQuery()
+  })
+}
+
+/** 处理课程类型节点点击 */
+const handleCourseTypeClick = (data) => {
+  queryParams.courseType = data.id
+  handleQuery()
 }
 
+/** 处理树形搜索 */
+const handleTreeSearch = () => {
+  // 搜索时自动清除当前选中的课程类型
+  queryParams.courseType = undefined
+}
+
+/** 过滤树形数据 */
+const filteredCourseTypeTree = computed(() => {
+  if (!treeSearchValue.value) {
+    return courseTypeTree.value
+  }
+
+  const filterTree = (nodes, keyword) => {
+    return nodes.map(node => {
+      const newNode = { ...node }
+      // 检查节点是否匹配搜索关键词
+      const isMatch = newNode.ctType && newNode.ctType.toLowerCase().includes(keyword.toLowerCase())
+
+      // 如果有子节点,递归过滤
+      if (newNode.children && newNode.children.length > 0) {
+        const filteredChildren = filterTree(newNode.children, keyword)
+
+        // 如果节点匹配或有匹配的子节点,则显示该节点
+        if (isMatch || filteredChildren.length > 0) {
+          newNode.children = filteredChildren
+          return newNode
+        }
+        return null
+      }
+
+      // 叶子节点如果匹配则显示
+      return isMatch ? newNode : null
+    }).filter(Boolean)
+  }
+
+  return filterTree(courseTypeTree.value, treeSearchValue.value)
+})
+
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value.resetFields()
   queryParams.ctTypeNode = "1"
-  getCourseTypeTree()
-  handleQuery()
+  queryParams.courseType = undefined
+  treeSearchValue.value = '' // 清空搜索框
+  getCourseTypeTree().then(() => {
+    handleQuery()
+  })
 }
 
 /** 添加/修改操作 */
@@ -350,7 +394,6 @@ const handleConfig = (id: number,courseName: string,tenantId: number) => {
   })
 }
 
-
 /** 导出按钮操作 */
 const handleExport = async () => {
   try {
@@ -375,9 +418,9 @@ const getCourseTypeTree = async (filterCtTypeNode = "1") => {
   if (filterCtTypeNode !== undefined) {
     filteredData = data.filter(item => item.ctTypeNode === '0' || item.ctTypeNode === filterCtTypeNode)
   }
-  const root: Tree = { id: 0, ctType: '课程类型' + (filterCtTypeNode === "1" ? '(ai通识课)' : '(ai实操课)'), children: [] }
+  const root = { id: 0, ctType: '课程类型' + (filterCtTypeNode === "1" ? '(ai通识课)' : '(ai实操课)'), children: [] }
   root.children = handleTree(filteredData, 'id', 'ctParentId')
-  courseTypeTree.value.push(root)
+  courseTypeTree.value = [root]
 }
 
 /** 初始化 **/
@@ -386,3 +429,32 @@ onMounted(() => {
   getCourseTypeTree()
 })
 </script>
+
+<style scoped>
+/* 优化滚动条样式 */
+:deep(.custom-scrollbar) {
+  scrollbar-width: thin;
+  scrollbar-color: #c0c4cc #f0f2f5;
+}
+
+/* 兼容WebKit浏览器(Chrome、Safari等) */
+:deep(.custom-scrollbar::-webkit-scrollbar) {
+  width: 3px;
+  height: 3px;
+}
+
+:deep(.custom-scrollbar::-webkit-scrollbar-track) {
+  background: #f0f2f5;
+  border-radius: 3px;
+}
+
+:deep(.custom-scrollbar::-webkit-scrollbar-thumb) {
+  background: #c0c4cc;
+  border-radius: 3px;
+  transition: background 0.3s;
+}
+
+:deep(.custom-scrollbar::-webkit-scrollbar-thumb:hover) {
+  background: #909399;
+}
+</style>

+ 319 - 196
src/views/blockly/blockly/index.vue

@@ -1,196 +1,232 @@
 <template>
-  <ContentWrap>
-    <!-- 搜索工作栏 -->
-    <el-form
-      class="-mb-15px"
-      :model="queryParams"
-      ref="queryFormRef"
-      :inline="true"
-      label-width="90px"
-    >
-      <el-form-item label="大纲课程" prop="bcType">
-        <el-tree-select
+  <el-row :gutter="20">
+    <!-- 左侧课程类型树 -->
+    <el-col :span="5" :xs="24">
+      <ContentWrap class="h-1/1 custom-scrollbar" style="overflow-x: auto; overflow-y: auto; height: calc(100vh - 100px);">
+        <!-- 课程类型切换 -->
+        <div class="mb-20px">
+          <el-form-item label="课程类型" class="!mb-0">
+            <el-select
+              v-model="queryParams.ctTypeNode"
+              placeholder="请选择课程类型"
+              class="!w-full"
+              @change="handleCtTypeNodeChange"
+            >
+              <el-option label="ai通识课" value="1" />
+              <el-option label="ai实操课" value="2" />
+            </el-select>
+          </el-form-item>
+        </div>
+
+        <!-- 搜索条件框 -->
+        <div class="mb-20px">
+          <el-input
+            v-model="treeSearchValue"
+            placeholder="搜索课程类型"
+            prefix-icon="ep:search"
+            clearable
+            @input="handleTreeSearch"
+            class="!w-full"
+          />
+        </div>
+
+        <!-- 课程类型树形选择器 -->
+        <el-tree
           v-model="queryParams.bcType"
-          :data="bcTypeTree"
-          :props="{...defaultProps,
-            label: (node) => `${node.ctTypeNode === undefined ? node.ctType : node.ctTypeSort + '、' + node.ctType}`,
-            }"
-          placeholder="请选择课程类型"
+          :data="filteredCourseTypeTree"
+          :props="{
+            label: (node) => `${node.ctTypeNode === '0' || node.ctTypeNode === undefined ? node.ctType : node.ctTypeSort + '、' + node.ctType}`,
+            children: 'children',
+            value: 'id'
+          }"
           :default-expand-all="true"
-          class="!w-240px"
-          @change="handleQuery"
+          node-key="id"
+          highlight-current
+          @node-click="handleCourseTypeClick"
         />
-      </el-form-item>
-      <el-form-item label="内容类型" prop="bcContentType">
-        <el-select
-          v-model="queryParams.bcContentType"
-          placeholder="请选择内容类型"
-          clearable
-          class="!w-240px"
-          @change="handleQuery"
+      </ContentWrap>
+    </el-col>
+    <el-col :span="19" :xs="24">
+      <!-- 搜索工作栏 -->
+      <ContentWrap>
+        <el-form
+          class="-mb-15px"
+          :model="queryParams"
+          ref="queryFormRef"
+          :inline="true"
+          label-width="90px"
         >
-          <el-option
-            v-for="dict in getStrDictOptions(DICT_TYPE.BLOCKLY_COURSE_COUTNET_TYPE)"
-            :key="dict.value"
-            :label="dict.label"
-            :value="dict.value"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="课程名称" prop="bcName">
-        <el-input
-          v-model="queryParams.bcName"
-          placeholder="请输入课程名称"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
+          <el-form-item label="内容类型" prop="bcContentType">
+            <el-select
+              v-model="queryParams.bcContentType"
+              placeholder="请选择内容类型"
+              clearable
+              class="!w-240px"
+              @change="handleQuery"
+            >
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.BLOCKLY_COURSE_COUTNET_TYPE)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="课程名称" prop="bcName">
+            <el-input
+              v-model="queryParams.bcName"
+              placeholder="请输入课程名称"
+              clearable
+              @keyup.enter="handleQuery"
+              class="!w-240px"
+            />
+          </el-form-item>
+          <el-form-item label="是否有检查" prop="bcIsInspect">
+            <el-select
+              v-model="queryParams.bcIsInspect"
+              placeholder="请选择是否有检查"
+              clearable
+              class="!w-240px"
+              @change="handleQuery"
+            >
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="课程标签" prop="bcLabel">
+            <el-select
+              v-model="queryParams.bcLabel"
+              placeholder="请选择课程标签"
+              clearable
+              class="!w-240px"
+              @change="handleQuery"
+            >
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.BLOCKLY_COURSE_LABEL)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="课程状态" prop="bcStatus">
+            <el-select
+              v-model="queryParams.bcStatus"
+              placeholder="请选择课程状态"
+              clearable
+              class="!w-240px"
+              @change="handleQuery"
+            >
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.COMMON_STATUS)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+            <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+            <el-button
+              type="primary"
+              plain
+              @click="openForm('create')"
+              v-hasPermi="['blockly:blockly:create']"
+            >
+              <Icon icon="ep:plus" class="mr-5px" /> 新增
+            </el-button>
+            <el-button
+              type="success"
+              plain
+              @click="handleExport"
+              :loading="exportLoading"
+              v-hasPermi="['blockly:blockly:export']"
+            >
+              <Icon icon="ep:download" class="mr-5px" /> 导出
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </ContentWrap>
+
+      <!-- 列表 -->
+      <ContentWrap>
+        <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+          <el-table-column label="课程类型" align="center" prop="bcTypeName" />
+          <el-table-column label="课程名称" align="center" prop="bcName" />
+          <el-table-column label="内容类型" align="center" prop="bcContentType" >
+            <template #default="scope">
+              <dict-tag :type="DICT_TYPE.BLOCKLY_COURSE_COUTNET_TYPE" :value="scope.row.bcContentType" />
+            </template>
+          </el-table-column>
+          <el-table-column label="课程内容" align="center" prop="bcContent" width="120px">
+            【预览查看】
+          </el-table-column>
+          <el-table-column label="是否有检查" align="center" prop="bcIsInspect">
+            <template #default="scope">
+              <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.bcIsInspect" />
+            </template>
+          </el-table-column>
+          <el-table-column label="课程标签" align="center" prop="bcLabel">
+            <template #default="scope">
+              <dict-tag :type="DICT_TYPE.BLOCKLY_COURSE_LABEL" :value="scope.row.bcLabel" />
+            </template>
+          </el-table-column>
+          <el-table-column label="课程排序" align="center" prop="bcOrder"/>
+          <el-table-column label="课程状态" align="center" prop="bcStatus">
+            <template #default="scope">
+              <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.bcStatus" />
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" align="center" min-width="180px">
+            <template #default="scope">
+              <el-button
+                link
+                type="primary"
+                v-if="scope.row.tenantId == getTenantId()"
+                @click="openForm('update', scope.row.id)"
+                v-hasPermi="['blockly:blockly:update']"
+              >
+                编辑
+              </el-button>
+              <el-button
+                link
+                type="success"
+                :disabled="scope.row.bcContentType !== 'video'"
+                title="仅视频课程可配置"
+                @click="handleConfig(scope.row.id,scope.row.bcName,scope.row.tenantId)"
+              >
+                配置
+              </el-button>
+              <el-button
+                link
+                type="danger"
+                v-if="scope.row.tenantId == getTenantId()"
+                @click="handleDelete(scope.row.id)"
+                v-hasPermi="['blockly:blockly:delete']"
+              >
+                删除
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <!-- 分页 -->
+        <Pagination
+          :total="total"
+          v-model:page="queryParams.pageNo"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
         />
-      </el-form-item>
-      <el-form-item label="是否有检查" prop="bcIsInspect">
-        <el-select
-          v-model="queryParams.bcIsInspect"
-          placeholder="请选择是否有检查"
-          clearable
-          class="!w-240px"
-          @change="handleQuery"
-        >
-          <el-option
-            v-for="dict in getStrDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
-            :key="dict.value"
-            :label="dict.label"
-            :value="dict.value"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="课程标签" prop="bcLabel">
-        <el-select
-          v-model="queryParams.bcLabel"
-          placeholder="请选择课程标签"
-          clearable
-          class="!w-240px"
-          @change="handleQuery"
-        >
-          <el-option
-            v-for="dict in getStrDictOptions(DICT_TYPE.BLOCKLY_COURSE_LABEL)"
-            :key="dict.value"
-            :label="dict.label"
-            :value="dict.value"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="课程状态" prop="bcStatus">
-        <el-select
-          v-model="queryParams.bcStatus"
-          placeholder="请选择课程状态"
-          clearable
-          class="!w-240px"
-          @change="handleQuery"
-        >
-          <el-option
-            v-for="dict in getStrDictOptions(DICT_TYPE.COMMON_STATUS)"
-            :key="dict.value"
-            :label="dict.label"
-            :value="dict.value"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item>
-        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
-        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
-        <el-button
-          type="primary"
-          plain
-          @click="openForm('create')"
-          v-hasPermi="['blockly:blockly:create']"
-        >
-          <Icon icon="ep:plus" class="mr-5px" /> 新增
-        </el-button>
-        <el-button
-          type="success"
-          plain
-          @click="handleExport"
-          :loading="exportLoading"
-          v-hasPermi="['blockly:blockly:export']"
-        >
-          <Icon icon="ep:download" class="mr-5px" /> 导出
-        </el-button>
-      </el-form-item>
-    </el-form>
-  </ContentWrap>
-
-  <!-- 列表 -->
-  <ContentWrap>
-    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
-      <el-table-column label="课程类型" align="center" prop="bcTypeName" />
-      <el-table-column label="课程名称" align="center" prop="bcName" />
-      <el-table-column label="内容类型" align="center" prop="bcContentType" >
-        <template #default="scope">
-          <dict-tag :type="DICT_TYPE.BLOCKLY_COURSE_COUTNET_TYPE" :value="scope.row.bcContentType" />
-        </template>
-      </el-table-column>
-      <el-table-column label="课程内容" align="center" prop="bcContent" width="120px">
-          【预览查看】
-      </el-table-column>
-      <el-table-column label="是否有检查" align="center" prop="bcIsInspect">
-        <template #default="scope">
-          <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.bcIsInspect" />
-        </template>
-      </el-table-column>
-      <el-table-column label="课程标签" align="center" prop="bcLabel">
-        <template #default="scope">
-          <dict-tag :type="DICT_TYPE.BLOCKLY_COURSE_LABEL" :value="scope.row.bcLabel" />
-        </template>
-      </el-table-column>
-      <el-table-column label="课程排序" align="center" prop="bcOrder"/>
-      <el-table-column label="课程状态" align="center" prop="bcStatus">
-        <template #default="scope">
-          <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.bcStatus" />
-        </template>
-      </el-table-column>
-      <el-table-column label="操作" align="center" min-width="180px"> <!-- 调整列宽适配新按钮 -->
-        <template #default="scope">
-          <el-button
-            link
-            type="primary"
-            v-if="scope.row.tenantId == getTenantId()"
-            @click="openForm('update', scope.row.id)"
-            v-hasPermi="['blockly:blockly:update']"
-          >
-            编辑
-          </el-button>
-          <el-button
-            link
-            type="success"
-            :disabled="scope.row.bcContentType !== 'video'"
-            title="仅视频课程可配置"
-            @click="handleConfig(scope.row.id,scope.row.bcName,scope.row.tenantId)"
-          >
-            配置
-          </el-button>
-          <el-button
-            link
-            type="danger"
-            v-if="scope.row.tenantId == getTenantId()"
-            @click="handleDelete(scope.row.id)"
-            v-hasPermi="['blockly:blockly:delete']"
-          >
-            删除
-          </el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-    <!-- 分页 -->
-    <Pagination
-      :total="total"
-      v-model:page="queryParams.pageNo"
-      v-model:limit="queryParams.pageSize"
-      @pagination="getList"
-    />
-  </ContentWrap>
+      </ContentWrap>
+    </el-col>
+  </el-row>
 
   <!-- 表单弹窗:添加/修改 -->
   <BlocklyForm ref="formRef" @success="getList" />
-
 </template>
 
 <script setup lang="ts">
@@ -199,10 +235,9 @@ import download from '@/utils/download'
 import { BlocklyApi, BlocklyVO } from '@/api/blockly/blockly'
 import BlocklyForm from './BlocklyForm.vue'
 import { useRouter } from 'vue-router'
-import { defaultProps, handleTree } from '@/utils/tree'
+import { handleTree } from '@/utils/tree'
 import { BlocklyTypeApi } from '@/api/blockly/blocklyType'
 import { getTenantId } from '@/utils/auth'
-import { ElButton } from 'element-plus'
 
 /** 课程 列表 */
 defineOptions({ name: 'Blockly' })
@@ -213,6 +248,7 @@ const { t } = useI18n() // 国际化
 const loading = ref(true) // 列表的加载中
 const list = ref<BlocklyVO[]>([]) // 列表的数据
 const total = ref(0) // 列表的总页数
+const treeSearchValue = ref('') // 树形搜索值
 const queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -229,6 +265,7 @@ const queryParams = reactive({
   blocklyWalkablePoints: undefined,
 
   bcIsInspect: undefined,
+  ctTypeNode: "1",//课程类型
   bcType: undefined,
   bcTypeName: undefined,
   bcLabel: undefined,
@@ -237,7 +274,37 @@ const queryParams = reactive({
 })
 const queryFormRef = ref() // 搜索的表单
 const exportLoading = ref(false) // 导出的加载中
-const bcTypeTree = ref() // 树形结构
+const bcTypeTree = ref() // 原始树形结构
+const filteredCourseTypeTree = computed(() => {
+  if (!treeSearchValue.value) {
+    return bcTypeTree.value
+  }
+
+  const filterTree = (tree, searchText) => {
+    return tree.map(node => {
+      const newNode = { ...node }
+      // 检查节点是否匹配搜索文本
+      const isMatch = newNode.ctType && newNode.ctType.toLowerCase().includes(searchText.toLowerCase())
+
+      // 如果有子节点,递归过滤
+      if (newNode.children && newNode.children.length > 0) {
+        const filteredChildren = filterTree(newNode.children, searchText)
+        if (filteredChildren.length > 0 || isMatch) {
+          newNode.children = filteredChildren
+          return newNode
+        }
+      } else if (isMatch) {
+        // 没有子节点但节点本身匹配
+        return newNode
+      }
+
+      // 如果既没有匹配的子节点也不匹配自身,则返回null
+      return null
+    }).filter(node => node !== null) // 过滤掉null值
+  }
+
+  return filterTree([...bcTypeTree.value], treeSearchValue.value)
+})
 
 /** 查询列表 */
 const getList = async () => {
@@ -257,11 +324,35 @@ const handleQuery = async () => {
   getList()
 }
 
+/** 处理课程类型节点变更 */
+const handleCtTypeNodeChange = (ctTypeNode) => {
+  queryParams.bcType = undefined
+  getbcTypeTree(ctTypeNode).then(() => {
+    // 选择课程类型后自动搜索
+    handleQuery()
+  })
+}
+
+/** 处理课程类型节点点击 */
+const handleCourseTypeClick = (data) => {
+  queryParams.bcType = data.id
+  handleQuery()
+}
+
+/** 处理树搜索 */
+const handleTreeSearch = () => {
+  // 搜索时不需要自动查询列表,只过滤树节点
+}
+
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value.resetFields()
-  getbcTypeTree()
-  handleQuery()
+  queryParams.ctTypeNode = "1"
+  queryParams.bcType = undefined
+  treeSearchValue.value = ''
+  getbcTypeTree().then(() => {
+    handleQuery()
+  })
 }
 
 /** 添加/修改操作 */
@@ -285,14 +376,13 @@ const handleDelete = async (id: number) => {
 
 /** 配置按钮操作 */
 const router = useRouter()
-const handleConfig = (id: number,bcName: string,tenantId: number) => {
+const handleConfig = (id: number, bcName: string, tenantId: number) => {
   router.push({
     path: '/blockly/blockly-config',
-    query: { bcId: id , bcName: bcName, tenantId: tenantId}
+    query: { bcId: id, bcName: bcName, tenantId: tenantId }
   })
 }
 
-
 /** 导出按钮操作 */
 const handleExport = async () => {
   try {
@@ -309,13 +399,17 @@ const handleExport = async () => {
 }
 
 /** 获得课程-类型树 */
-const getbcTypeTree = async () => {
+const getbcTypeTree = async (filterCtTypeNode = "1") => {
   bcTypeTree.value = []
   const data = await BlocklyTypeApi.getBlocklyTypeSimpleList()
 
-  const root: Tree = { id: 0, ctType: '课程类型', children: [] }
-  root.children = handleTree(data, 'id', 'ctParentId')
-  bcTypeTree.value.push(root)
+  let filteredData = data
+  if (filterCtTypeNode !== undefined) {
+    filteredData = data.filter(item => item.ctTypeNode === '0' || item.ctTypeNode === filterCtTypeNode)
+  }
+  const root = { id: 0, ctType: '课程类型' + (filterCtTypeNode === "1" ? '(ai通识课)' : '(ai实操课)'), children: [] }
+  root.children = handleTree(filteredData, 'id', 'ctParentId')
+  bcTypeTree.value = [root]
 }
 
 /** 初始化 **/
@@ -324,3 +418,32 @@ onMounted(() => {
   getbcTypeTree()
 })
 </script>
+
+<style scoped>
+/* 优化滚动条样式 */
+:deep(.custom-scrollbar) {
+  scrollbar-width: thin;
+  scrollbar-color: #c0c4cc #f0f2f5;
+}
+
+/* 兼容WebKit浏览器(Chrome、Safari等) */
+:deep(.custom-scrollbar::-webkit-scrollbar) {
+  width: 3px;
+  height: 3px;
+}
+
+:deep(.custom-scrollbar::-webkit-scrollbar-track) {
+  background: #f0f2f5;
+  border-radius: 3px;
+}
+
+:deep(.custom-scrollbar::-webkit-scrollbar-thumb) {
+  background: #c0c4cc;
+  border-radius: 3px;
+  transition: background 0.3s;
+}
+
+:deep(.custom-scrollbar::-webkit-scrollbar-thumb:hover) {
+  background: #909399;
+}
+</style>