a
This commit is contained in:
@@ -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>
|
||||
Reference in New Issue
Block a user