This commit is contained in:
Ubuntu
2026-07-03 16:58:28 +08:00
commit 32b43f85bd
6240 changed files with 1987678 additions and 0 deletions
@@ -0,0 +1,362 @@
<template>
<view class="category-tree-container">
<!-- 搜索栏 -->
<view class="search-section" v-if="showSearch">
<view class="search-input" @click="handleSearchClick">
<text class="search-icon">🔍</text>
<text class="search-placeholder">搜索体系分类...</text>
</view>
</view>
<!-- 分类树 -->
<scroll-view
class="category-scroll"
scroll-y
:scroll-with-animation="true"
:show-scrollbar="false"
>
<!-- 空状态 -->
<empty-state
v-if="!loading && categories.length === 0"
:title="'暂无分类'"
:description="'暂无体系分类数据'"
:show-action="true"
:action-text="'刷新'"
@action="$emit('refresh')"
/>
<!-- 分类列表 -->
<view v-else class="category-list">
<view
v-for="category in categories"
:key="category.id"
class="category-item"
:class="{
'category-level-1': true,
'expanded': category.expanded,
'selected': selectedCategory?.id === category.id
}"
>
<!-- 一级分类 -->
<view
class="category-header"
@click="handleCategoryClick(category)"
>
<view class="category-info">
<text class="category-icon">📚</text>
<text class="category-name">{{ category.name }}</text>
<text class="category-count" v-if="category.children.length > 0">
({{ category.children.length }})
</text>
</view>
<view class="category-actions">
<!-- 展开/收起箭头 -->
<text
class="expand-icon"
v-if="category.children.length > 0"
@click.stop="toggleCategoryExpand(category)"
>
{{ category.expanded ? '▼' : '▶' }}
</text>
<!-- 选中标记 -->
<text
class="selected-icon"
v-if="selectedCategory?.id === category.id"
>
✓
</text>
</view>
</view>
<!-- 二级分类(子分类) -->
<view
class="subcategory-list"
v-if="category.expanded && category.children.length > 0"
>
<view
v-for="child in category.children"
:key="child.id"
class="subcategory-item"
:class="{
'category-level-2': true,
'selected': selectedCategory?.id === child.id
}"
@click="handleSubcategoryClick(child, category)"
>
<view class="subcategory-info">
<text class="subcategory-icon">📖</text>
<text class="subcategory-name">{{ child.name }}</text>
</view>
<text
class="selected-icon"
v-if="selectedCategory?.id === child.id"
>
✓
</text>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
import EmptyState from '@/components/common/empty-state.vue'
export default {
name: 'CategoryTree',
components: {
EmptyState
},
props: {
// 分类数据
categories: {
type: Array,
default: () => []
},
// 选中的分类
selectedCategory: {
type: Object,
default: null
},
// 是否显示搜索
showSearch: {
type: Boolean,
default: true
},
// 加载状态
loading: {
type: Boolean,
default: false
}
},
data() {
return {
// 本地状态
}
},
methods: {
// 处理分类点击
handleCategoryClick(category) {
this.$emit('category-click', category)
},
// 处理子分类点击
handleSubcategoryClick(childCategory, parentCategory) {
this.$emit('subcategory-click', {
...childCategory,
parentCategory: {
id: parentCategory.id,
name: parentCategory.name
}
})
},
// 切换分类展开状态
toggleCategoryExpand(category) {
this.$emit('toggle-expand', {
...category,
expanded: !category.expanded
})
},
// 处理搜索点击
handleSearchClick() {
this.$emit('search-click')
}
}
}
</script>
<style scoped>
.category-tree-container {
display: flex;
flex-direction: column;
height: 100%;
background-color: #f8f8f8;
}
/* 搜索栏 */
.search-section {
padding: 20rpx 30rpx;
background-color: #fff;
border-bottom: 1rpx solid #f0f0f0;
}
.search-input {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
background-color: #f8f8f8;
border-radius: 50rpx;
border: 1rpx solid #e5e5e5;
}
.search-icon {
font-size: 32rpx;
margin-right: 16rpx;
color: #999;
}
.search-placeholder {
font-size: 28rpx;
color: #999;
flex: 1;
}
/* 分类滚动区域 */
.category-scroll {
flex: 1;
}
/* 分类列表 */
.category-list {
padding: 20rpx 0;
}
/* 一级分类 */
.category-item {
margin-bottom: 10rpx;
background-color: #fff;
border-radius: 16rpx;
overflow: hidden;
transition: all 0.3s ease;
}
.category-item.selected {
background-color: #f0f9ff;
border-left: 6rpx solid #3cc51f;
}
.category-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
cursor: pointer;
transition: all 0.3s ease;
}
.category-header:active {
background-color: #f8f8f8;
}
.category-info {
display: flex;
align-items: center;
flex: 1;
}
.category-icon {
font-size: 36rpx;
margin-right: 20rpx;
color: #3cc51f;
}
.category-name {
font-size: 32rpx;
font-weight: 600;
color: #333;
flex: 1;
}
.category-count {
font-size: 24rpx;
color: #999;
margin-left: 12rpx;
}
.category-actions {
display: flex;
align-items: center;
gap: 20rpx;
}
.expand-icon {
font-size: 24rpx;
color: #999;
padding: 10rpx;
transition: transform 0.3s ease;
}
.expand-icon:active {
color: #3cc51f;
}
.selected-icon {
font-size: 28rpx;
color: #3cc51f;
font-weight: bold;
}
/* 二级分类列表 */
.subcategory-list {
background-color: #fafafa;
border-top: 1rpx solid #f0f0f0;
padding: 0 30rpx;
}
.subcategory-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 25rpx 0;
border-bottom: 1rpx solid #f0f0f0;
cursor: pointer;
transition: all 0.3s ease;
}
.subcategory-item:last-child {
border-bottom: none;
}
.subcategory-item:active {
background-color: #f5f5f5;
}
.subcategory-item.selected {
background-color: #f0f9ff;
}
.subcategory-info {
display: flex;
align-items: center;
flex: 1;
}
.subcategory-icon {
font-size: 28rpx;
margin-right: 20rpx;
color: #666;
}
.subcategory-name {
font-size: 28rpx;
color: #666;
flex: 1;
}
/* 动画效果 */
.category-item.expanded .expand-icon {
transform: rotate(90deg);
}
/* 悬停效果(在支持hover的设备上) */
@media (hover: hover) {
.category-header:hover {
background-color: #f8f8f8;
}
.subcategory-item:hover {
background-color: #f5f5f5;
}
.expand-icon:hover {
color: #3cc51f;
}
}
</style>