完善团课前后端交互

This commit is contained in:
2026-06-15 15:49:21 +08:00
parent 96b8fd2534
commit 4e69185c48
7 changed files with 880 additions and 83 deletions
@@ -1,5 +1,20 @@
<template>
<view class="filter-section">
<!-- 课程类型筛选 -->
<picker
mode="selector"
:range="courseTypeOptions"
range-key="label"
:value="courseTypeIndex"
@change="onCourseTypeChange"
>
<view class="filter-item">
<uni-icons type="apps" size="18" color="#5E6F8D" class="filter-icon" />
<text class="filter-text">{{ courseTypeOptions[courseTypeIndex]?.label || '全部类型' }}</text>
<uni-icons type="right" size="20" color="#A0AEC0" class="filter-arrow" />
</view>
</picker>
<!-- 时间区间筛选 -->
<view class="filter-item" @click="handleTimePick">
<uni-icons type="calendar" size="18" color="#5E6F8D" class="filter-icon" />
@@ -25,7 +40,7 @@
</template>
<script setup>
import { ref, watch } from 'vue'
import { ref, watch, computed } from 'vue'
const props = defineProps({
timeRangeText: {
@@ -35,46 +50,90 @@ const props = defineProps({
sortOptions: {
type: Array,
default: () => [
{ label: '默认排序', value: 'default' },
{ label: '价格从低到高', value: 'priceAsc' },
{ label: '价格从高到低', value: 'priceDesc' },
{ label: '剩余名额最多', value: 'spotsDesc' },
{ label: '仅次数卡', value: 'pointCardOnly' },
{ label: '仅储值卡', value: 'storedValueOnly' },
{ label: '两种支付', value: 'bothPayment' }
{ label: '默认排序', value: 'default', priceSort: null, remainingMost: false },
{ label: '价格从低到高', value: 'priceAsc', priceSort: 'asc', remainingMost: false },
{ label: '价格从高到低', value: 'priceDesc', priceSort: 'desc', remainingMost: false },
{ label: '剩余名额最多', value: 'remainingMost', priceSort: null, remainingMost: true }
]
},
sortIndex: {
type: Number,
default: 0
},
courseTypes: {
type: Array,
default: () => []
},
currentCourseTypeId: {
type: [Number, String, null],
default: null,
validator: (val) => val === null || val === '' || !isNaN(Number(val))
}
})
const emit = defineEmits(['update:sortIndex', 'timePick'])
const emit = defineEmits(['update:sortIndex', 'timePick', 'courseTypeChange'])
const localSortIndex = ref(props.sortIndex)
const courseTypeOptions = computed(() => {
return [{ id: null, label: '全部类型' }, ...props.courseTypes]
})
const courseTypeIndex = computed(() => {
if (props.currentCourseTypeId === null || props.currentCourseTypeId === '') return 0
const currentId = Number(props.currentCourseTypeId)
const index = courseTypeOptions.value.findIndex(item => Number(item.id) === currentId)
return index >= 0 ? index : 0
})
watch(() => props.sortIndex, (val) => {
localSortIndex.value = val
})
const onSortChange = (e) => {
localSortIndex.value = e.detail.value
const sortOption = props.sortOptions[localSortIndex.value]
console.log('[FilterSection] 排序方式变更:', {
index: localSortIndex.value,
value: props.sortOptions[localSortIndex.value]
value: sortOption
})
if (sortOption.priceSort && sortOption.remainingMost) {
console.warn('[FilterSection] 排序参数冲突警告: priceSort和remainingMost不能同时设置')
}
emit('update:sortIndex', localSortIndex.value)
}
const onCourseTypeChange = (e) => {
const index = e.detail.value
const selectedType = courseTypeOptions.value[index]
// 确保返回数字类型而非字符串
const typeId = selectedType.id !== null ? Number(selectedType.id) : null
console.log('[FilterSection] 课程类型变更:', {
index,
id: typeId,
label: selectedType.label
})
emit('courseTypeChange', typeId)
}
const handleTimePick = () => {
console.log('[FilterSection] 触发时间选择器')
emit('timePick')
}
const getFilterParams = () => {
const sortOption = props.sortOptions[localSortIndex.value]
const selectedType = courseTypeOptions.value[courseTypeIndex.value]
const params = {
sortType: props.sortOptions[localSortIndex.value].value,
sortType: sortOption.value,
priceSort: sortOption.priceSort,
remainingMost: sortOption.remainingMost,
courseTypeId: selectedType.id !== null ? Number(selectedType.id) : null,
courseTypeName: selectedType.label,
timeRangeText: props.timeRangeText
}
console.log('[FilterSection] 获取筛选参数:', params)
@@ -173,18 +232,20 @@ defineExpose({
<style lang="scss" scoped>
.filter-section {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
.filter-item {
flex: 1;
min-width: calc(33.33% - 12rpx);
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
padding: 20rpx 24rpx;
gap: 8rpx;
padding: 18rpx 16rpx;
background: #F5F7FA;
border-radius: 16rpx;
font-size: 26rpx;
font-size: 24rpx;
color: #5E6F8D;
.filter-icon {
@@ -197,6 +258,13 @@ defineExpose({
display: flex;
align-items: center;
}
.filter-text {
max-width: 100rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
</style>