From 82ba59f373dec5810cd7113dd608804d2fdad755 Mon Sep 17 00:00:00 2001 From: xcbyy <2578898740@qq.com> Date: Sat, 10 Oct 2026 09:57:04 +0800 Subject: [PATCH] feat(activity): connect dynamic category navigation to activity create and list views --- pwuniapp/pages/activity/create.vue | 25 ++++++-- pwuniapp/pages/activity/list.vue | 96 +++++++++++++++++++++--------- 2 files changed, 86 insertions(+), 35 deletions(-) diff --git a/pwuniapp/pages/activity/create.vue b/pwuniapp/pages/activity/create.vue index 7175cc2..51201fd 100644 --- a/pwuniapp/pages/activity/create.vue +++ b/pwuniapp/pages/activity/create.vue @@ -288,10 +288,10 @@ import { ref, computed, onMounted, onUnmounted } from 'vue'; import { onShow } from '@dcloudio/uni-app'; import { ICONS } from '@/common/icons.js'; -import { createActivity, getSafetyPlaces } from '@/common/api.js'; +import { createActivity, getSafetyPlaces, getNavCategories } from '@/common/api.js'; import { getCurrentThemeKey, applyThemeToNativeUI } from '@/common/theme.js'; -const games = ['美食陪吃', '同城陪唱', '下午茶陪喝', '同城微醺', '同城桌游', '热门电竞']; +const games = ref(['美食陪吃', '同城陪唱', '下午茶陪喝', '同城微醺', '同城桌游', '热门电竞']); const currentThemeKey = ref(getCurrentThemeKey()); const onThemeChanged = (key) => { @@ -351,14 +351,27 @@ const recommendPublicZones = ref([ const loadLivePlaces = async () => { try { - const list = await getSafetyPlaces(); - if (Array.isArray(list) && list.length > 0) { - recommendPublicZones.value = list + const [placesList, catList] = await Promise.allSettled([ + getSafetyPlaces(), + getNavCategories() + ]); + + if (placesList.status === 'fulfilled' && Array.isArray(placesList.value) && placesList.value.length > 0) { + recommendPublicZones.value = placesList.value .filter((p) => p.status === '正常营业') .map((p) => `${p.area} · ${p.name}`); } + + if (catList.status === 'fulfilled' && Array.isArray(catList.value) && catList.value.length > 0) { + const activeCats = catList.value + .filter((c) => c.status === 1 && c.name && c.name !== '全部活动') + .map((c) => c.name); + if (activeCats.length > 0) { + games.value = activeCats; + } + } } catch (e) { - console.warn('[ActivityCreate] 加载合规场所异常降级:', e); + console.warn('[ActivityCreate] 加载合规场所与品类异常降级:', e); } }; diff --git a/pwuniapp/pages/activity/list.vue b/pwuniapp/pages/activity/list.vue index 976d23b..ab24938 100644 --- a/pwuniapp/pages/activity/list.vue +++ b/pwuniapp/pages/activity/list.vue @@ -61,7 +61,7 @@ - + 全部品类 - - 美食陪吃 - - - - 同城陪唱 - - - - 下午茶陪喝 + + {{ cat.name }} @@ -190,7 +176,7 @@ import { ref, computed, onMounted, onUnmounted } from 'vue'; import { onShow, onLoad } from '@dcloudio/uni-app'; import CustomTabBar from '@/components/CustomTabBar.vue'; import SkeletonScreen from '@/components/SkeletonScreen.vue'; -import { getActivities } from '@/common/api.js'; +import { getActivities, getNavCategories } from '@/common/api.js'; import { ICONS } from '@/common/icons.js'; import { getCurrentThemeKey, applyThemeToNativeUI } from '@/common/theme.js'; import { getNavBarInfo } from '@/common/nav.js'; @@ -201,6 +187,7 @@ const isLoading = ref(true); const activities = ref([]); const currentTab = ref('ALL'); const currentCategory = ref('ALL'); +const dynamicCategories = ref([]); const currentThemeKey = ref(getCurrentThemeKey()); const searchKeyword = ref(''); const navInfo = ref(getNavBarInfo()); @@ -238,6 +225,43 @@ const fetchLiveActivities = async () => { } }; +const fetchLiveCategories = async () => { + try { + const res = await getNavCategories(); + if (Array.isArray(res) && res.length > 0) { + dynamicCategories.value = res.filter((c) => c.status === 1 && c.code !== 'more'); + } + } catch (e) { + console.warn('[ActivityList] 获取品类导航异常降级:', e); + } +}; + +const navCapsules = computed(() => { + if (dynamicCategories.value && dynamicCategories.value.length > 0) { + return dynamicCategories.value.map((c) => { + let icon = ICONS.gameSwords; + if (c.code === 'meal') icon = ICONS.utensils; + else if (c.code === 'sing') icon = ICONS.micVocal; + else if (c.code === 'drink' || c.code === 'bar') icon = ICONS.coffee; + else if (c.code === 'esports') icon = ICONS.gamepad; + + return { + code: c.code.toUpperCase(), + catKey: c.cat, + name: c.name, + iconSvg: icon + }; + }); + } + + // 默认兜底品类 + return [ + { code: 'MEAL', catKey: 'offline_meal', name: '美食陪吃', iconSvg: ICONS.utensils }, + { code: 'SING', catKey: 'offline_sing', name: '同城陪唱', iconSvg: ICONS.micVocal }, + { code: 'DRINK', catKey: 'offline_drink', name: '下午茶陪喝', iconSvg: ICONS.coffee } + ]; +}); + onLoad((options) => { if (options && options.category) { currentCategory.value = options.category; @@ -258,6 +282,7 @@ onMounted(() => { applyThemeToNativeUI(currentThemeKey.value); uni.$on('theme-change', onThemeChanged); loadInitialActivities(); + fetchLiveCategories(); }); onShow(() => { @@ -271,6 +296,7 @@ onShow(() => { uni.removeStorageSync('ACTIVITY_ACTIVE_TAB'); } fetchLiveActivities(); + fetchLiveCategories(); }); onUnmounted(() => { @@ -314,14 +340,26 @@ const filteredActivities = computed(() => { matchTab = a.payType === currentTab.value; } - // 3. 品类筛选 (美食陪吃 / 同城陪唱 / 下午茶陪喝/微醺) + // 3. 品类筛选 (支持动态匹配后台下发品类) let matchCat = true; - if (currentCategory.value === 'MEAL') { - matchCat = a.game === '美食陪吃'; - } else if (currentCategory.value === 'SING') { - matchCat = a.game === '同城陪唱'; - } else if (currentCategory.value === 'DRINK') { - matchCat = a.game === '下午茶陪喝' || a.game === '同城微醺'; + if (currentCategory.value && currentCategory.value !== 'ALL') { + const targetCatCode = currentCategory.value.toUpperCase(); + if (targetCatCode === 'MEAL') { + matchCat = a.game === '美食陪吃' || (a.gameCategory || '').includes('MEAL'); + } else if (targetCatCode === 'SING') { + matchCat = a.game === '同城陪唱' || (a.gameCategory || '').includes('SING'); + } else if (targetCatCode === 'DRINK' || targetCatCode === 'BAR') { + matchCat = a.game === '下午茶陪喝' || a.game === '同城微醺' || (a.gameCategory || '').includes('DRINK'); + } else if (targetCatCode === 'ESPORTS') { + matchCat = a.game.includes('电竞') || a.game.includes('游戏') || (a.gameCategory || '').includes('ESPORTS'); + } else { + const found = navCapsules.value.find((c) => c.code === targetCatCode); + if (found) { + matchCat = a.game.includes(found.name) || found.name.includes(a.game); + } else { + matchCat = a.game.includes(currentCategory.value); + } + } } return matchKeyword && matchTab && matchCat; });