daShangDao_miniProgram/components/CategoryDropdown.vue
2025-11-24 10:25:20 +08:00

338 lines
8.7 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- components/CategoryDropdown.vue -->
<template>
<view class="category-dropdown">
<view class="select-box" @click="toggleDropdown">
<text class="selected-text">{{ displayText }}</text>
<view class="arrow" :class="{ 'arrow-up': showDropdown }"></view>
</view>
<view class="dropdown-list" v-if="showDropdown">
<scroll-view scroll-y style="max-height: 400rpx;">
<!-- 调试信息 -->
<view v-if="categories.length === 0" class="dropdown-item">
<text>加载中或无数据({{loading ? '加载中' : '无数据'}})</text>
</view>
<!-- 一级分类 -->
<view v-if="currentLevel === 1">
<view
v-for="(item, index) in categories"
:key="index"
class="dropdown-item"
@click="selectLevel1(item)"
>
<text>{{ item.name }}</text>
<text v-if="item.children && item.children.length" class="arrow-right"></text>
</view>
</view>
<!-- 二级分类 -->
<view v-else-if="currentLevel === 2">
<view class="dropdown-header" @click="backToLevel1">
<text class="back-icon"></text>
<text>返回</text>
</view>
<view
v-for="(item, index) in currentParent.children"
:key="index"
class="dropdown-item"
@click="selectLevel2(item)"
>
<text>{{ item.name }}</text>
<text v-if="item.children && item.children.length" class="arrow-right"></text>
</view>
</view>
<!-- 三级分类 -->
<view v-else-if="currentLevel === 3">
<view class="dropdown-header" @click="backToLevel2">
<text class="back-icon"></text>
<text>返回</text>
</view>
<view
v-for="(item, index) in currentParent.children"
:key="index"
class="dropdown-item"
@click="selectCategory(item)"
>
<text>{{ item.name }}</text>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import { getCategory } from '@/service/categoryService.js';
export default {
name: 'CategoryDropdown',
props: {
placeholder: {
type: String,
default: '请选择分类'
},
value: {
type: [Object, String, Number],
default: null
},
disabled: {
type: Boolean,
default: false
},
externalCategories: {
type: Array,
default: () => []
}
},
data() {
return {
categories: [],
selectedCategory: null,
showDropdown: false,
loading: false,
currentLevel: 1,
currentParent: null,
level1Selection: null,
level2Selection: null
};
},
computed: {
displayText() {
if (this.selectedCategory) {
let text = this.selectedCategory.name;
// 如果有上级分类,添加路径
if (this.level2Selection) {
text = `${this.level2Selection.name} > ${text}`;
}
if (this.level1Selection) {
text = `${this.level1Selection.name} > ${text}`;
}
return text;
}
return this.placeholder;
}
},
watch: {
// 监听外部传入的分类数据变化
externalCategories: {
handler(newVal) {
if (newVal && newVal.length > 0) {
console.log('从外部接收到分类数据:', newVal);
this.categories = newVal;
console.log('设置分类数据完成当前categories:', this.categories);
}
},
immediate: true,
deep: true
}
},
created() {
// 如果没有外部传入的分类数据,才自动获取
if (!this.externalCategories || this.externalCategories.length === 0) {
this.fetchCategories();
}
// 如果有初始值,设置选中项
if (this.value) {
this.selectedCategory = this.value;
}
},
methods: {
async fetchCategories(cookiesParam) {
this.loading = true;
try {
// 如果没有传入cookies从本地存储获取
const cookies = cookiesParam || uni.getStorageSync('cookies');
console.log('正在获取分类数据cookies:', cookies);
const result = await getCategory(cookies);
console.log('获取到的分类数据:', result);
if (result) {
// 处理不同的数据格式情况
if (result.successResponse && Array.isArray(result.successResponse)) {
this.categories = result.successResponse;
console.log('成功解析分类数据,数量:', this.categories);
} else if (Array.isArray(result)) {
this.categories = result;
console.log('成功解析分类数据(数组格式),数量:', this.categories.length);
} else {
console.error('分类数据格式不正确:', result);
uni.showToast({
title: '分类数据格式不正确',
icon: 'none',
duration: 2000
});
}
} else {
console.error('未获取到分类数据');
uni.showToast({
title: '获取分类列表失败',
icon: 'none',
duration: 2000
});
}
} catch (error) {
console.error('获取分类失败:', error);
uni.showToast({
title: '获取分类列表失败',
icon: 'none',
duration: 2000
});
} finally {
this.loading = false;
}
},
toggleDropdown() {
if (this.loading || this.disabled) return;
// 添加调试信息
console.log('toggleDropdown被触发当前categories:', this.categories);
console.log('当前categories长度:', this.categories.length);
if (!this.showDropdown) {
// 重置当前级别为1
this.currentLevel = 1;
this.currentParent = null;
}
this.showDropdown = !this.showDropdown;
},
selectLevel1(category) {
if (category.children && category.children.length) {
this.level1Selection = category;
this.currentParent = category;
this.currentLevel = 2;
} else {
this.selectCategory(category);
}
},
selectLevel2(category) {
if (category.children && category.children.length) {
this.level2Selection = category;
this.currentParent = category;
this.currentLevel = 3;
} else {
this.selectCategory(category);
}
},
selectCategory(category) {
this.selectedCategory = category;
this.showDropdown = false;
// 向父组件发送选中的值
this.$emit('input', category);
this.$emit('change', category);
},
backToLevel1() {
this.currentLevel = 1;
this.currentParent = null;
this.level2Selection = null;
},
backToLevel2() {
this.currentLevel = 2;
this.currentParent = this.level1Selection;
},
// 关闭下拉框,用于点击外部区域时调用
closeDropdown() {
this.showDropdown = false;
},
// 添加一个手动刷新分类数据的方法
refreshCategories(cookies) {
console.log('手动刷新分类数据cookies:', cookies);
this.fetchCategories(cookies);
}
}
};
</script>
<style scoped>
.category-dropdown {
position: relative;
width: 100%;
z-index: 10;
}
.select-box {
display: flex;
align-items: center;
justify-content: space-between;
height: 80rpx;
padding: 0 20rpx;
background-color: #ffffff;
border: 1px solid #e5e5e5;
border-radius: 8rpx;
}
.selected-text {
font-size: 28rpx;
color: #333;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 90%;
}
.arrow {
width: 0;
height: 0;
border-left: 12rpx solid transparent;
border-right: 12rpx solid transparent;
border-top: 12rpx solid #666;
transition: transform 0.3s;
}
.arrow-up {
transform: rotate(180deg);
}
.dropdown-list {
position: absolute;
top: 90rpx;
left: 0;
width: 100%;
background-color: #fff;
border: 1px solid #e5e5e5;
border-radius: 8rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
z-index: 11;
}
.dropdown-item {
padding: 20rpx;
font-size: 28rpx;
color: #333;
border-bottom: 1px solid #f5f5f5;
display: flex;
justify-content: space-between;
align-items: center;
}
.dropdown-item:last-child {
border-bottom: none;
}
.dropdown-item:active {
background-color: #f5f5f5;
}
.arrow-right {
font-size: 36rpx;
color: #999;
}
.dropdown-header {
padding: 20rpx;
font-size: 28rpx;
color: #007AFF;
border-bottom: 1px solid #f5f5f5;
display: flex;
align-items: center;
background-color: #f8f8f8;
}
.back-icon {
font-size: 36rpx;
margin-right: 10rpx;
}
</style>