feat(activity): connect dynamic category navigation to activity create and list views
这个提交包含在:
@@ -288,10 +288,10 @@
|
|||||||
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
||||||
import { onShow } from '@dcloudio/uni-app';
|
import { onShow } from '@dcloudio/uni-app';
|
||||||
import { ICONS } from '@/common/icons.js';
|
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';
|
import { getCurrentThemeKey, applyThemeToNativeUI } from '@/common/theme.js';
|
||||||
|
|
||||||
const games = ['美食陪吃', '同城陪唱', '下午茶陪喝', '同城微醺', '同城桌游', '热门电竞'];
|
const games = ref(['美食陪吃', '同城陪唱', '下午茶陪喝', '同城微醺', '同城桌游', '热门电竞']);
|
||||||
const currentThemeKey = ref(getCurrentThemeKey());
|
const currentThemeKey = ref(getCurrentThemeKey());
|
||||||
|
|
||||||
const onThemeChanged = (key) => {
|
const onThemeChanged = (key) => {
|
||||||
@@ -351,14 +351,27 @@ const recommendPublicZones = ref([
|
|||||||
|
|
||||||
const loadLivePlaces = async () => {
|
const loadLivePlaces = async () => {
|
||||||
try {
|
try {
|
||||||
const list = await getSafetyPlaces();
|
const [placesList, catList] = await Promise.allSettled([
|
||||||
if (Array.isArray(list) && list.length > 0) {
|
getSafetyPlaces(),
|
||||||
recommendPublicZones.value = list
|
getNavCategories()
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (placesList.status === 'fulfilled' && Array.isArray(placesList.value) && placesList.value.length > 0) {
|
||||||
|
recommendPublicZones.value = placesList.value
|
||||||
.filter((p) => p.status === '正常营业')
|
.filter((p) => p.status === '正常营业')
|
||||||
.map((p) => `${p.area} · ${p.name}`);
|
.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) {
|
} catch (e) {
|
||||||
console.warn('[ActivityCreate] 加载合规场所异常降级:', e);
|
console.warn('[ActivityCreate] 加载合规场所与品类异常降级:', e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 核心品类快捷筛选胶囊栏 (陪吃·陪唱·陪喝) -->
|
<!-- 核心品类快捷筛选胶囊栏 (动态根据后台金刚区配置渲染) -->
|
||||||
<view class="category-capsule-bar">
|
<view class="category-capsule-bar">
|
||||||
<view
|
<view
|
||||||
class="capsule-item btn-active"
|
class="capsule-item btn-active"
|
||||||
@@ -71,28 +71,14 @@
|
|||||||
<text class="capsule-text">全部品类</text>
|
<text class="capsule-text">全部品类</text>
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view
|
||||||
|
v-for="cat in navCapsules"
|
||||||
|
:key="cat.code"
|
||||||
class="capsule-item btn-active"
|
class="capsule-item btn-active"
|
||||||
:class="{ active: currentCategory === 'MEAL' }"
|
:class="{ active: currentCategory === cat.code || currentCategory === cat.catKey }"
|
||||||
@click="switchCategory('MEAL')"
|
@click="switchCategory(cat.code)"
|
||||||
>
|
>
|
||||||
<image class="capsule-svg" :src="ICONS.utensils" mode="aspectFit" />
|
<image class="capsule-svg" :src="cat.iconSvg" mode="aspectFit" v-if="cat.iconSvg" />
|
||||||
<text class="capsule-text">美食陪吃</text>
|
<text class="capsule-text">{{ cat.name }}</text>
|
||||||
</view>
|
|
||||||
<view
|
|
||||||
class="capsule-item btn-active"
|
|
||||||
:class="{ active: currentCategory === 'SING' }"
|
|
||||||
@click="switchCategory('SING')"
|
|
||||||
>
|
|
||||||
<image class="capsule-svg" :src="ICONS.micVocal" mode="aspectFit" />
|
|
||||||
<text class="capsule-text">同城陪唱</text>
|
|
||||||
</view>
|
|
||||||
<view
|
|
||||||
class="capsule-item btn-active"
|
|
||||||
:class="{ active: currentCategory === 'DRINK' }"
|
|
||||||
@click="switchCategory('DRINK')"
|
|
||||||
>
|
|
||||||
<image class="capsule-svg" :src="ICONS.coffee" mode="aspectFit" />
|
|
||||||
<text class="capsule-text">下午茶陪喝</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -190,7 +176,7 @@ import { ref, computed, onMounted, onUnmounted } from 'vue';
|
|||||||
import { onShow, onLoad } from '@dcloudio/uni-app';
|
import { onShow, onLoad } from '@dcloudio/uni-app';
|
||||||
import CustomTabBar from '@/components/CustomTabBar.vue';
|
import CustomTabBar from '@/components/CustomTabBar.vue';
|
||||||
import SkeletonScreen from '@/components/SkeletonScreen.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 { ICONS } from '@/common/icons.js';
|
||||||
import { getCurrentThemeKey, applyThemeToNativeUI } from '@/common/theme.js';
|
import { getCurrentThemeKey, applyThemeToNativeUI } from '@/common/theme.js';
|
||||||
import { getNavBarInfo } from '@/common/nav.js';
|
import { getNavBarInfo } from '@/common/nav.js';
|
||||||
@@ -201,6 +187,7 @@ const isLoading = ref(true);
|
|||||||
const activities = ref([]);
|
const activities = ref([]);
|
||||||
const currentTab = ref('ALL');
|
const currentTab = ref('ALL');
|
||||||
const currentCategory = ref('ALL');
|
const currentCategory = ref('ALL');
|
||||||
|
const dynamicCategories = ref([]);
|
||||||
const currentThemeKey = ref(getCurrentThemeKey());
|
const currentThemeKey = ref(getCurrentThemeKey());
|
||||||
const searchKeyword = ref('');
|
const searchKeyword = ref('');
|
||||||
const navInfo = ref(getNavBarInfo());
|
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) => {
|
onLoad((options) => {
|
||||||
if (options && options.category) {
|
if (options && options.category) {
|
||||||
currentCategory.value = options.category;
|
currentCategory.value = options.category;
|
||||||
@@ -258,6 +282,7 @@ onMounted(() => {
|
|||||||
applyThemeToNativeUI(currentThemeKey.value);
|
applyThemeToNativeUI(currentThemeKey.value);
|
||||||
uni.$on('theme-change', onThemeChanged);
|
uni.$on('theme-change', onThemeChanged);
|
||||||
loadInitialActivities();
|
loadInitialActivities();
|
||||||
|
fetchLiveCategories();
|
||||||
});
|
});
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
@@ -271,6 +296,7 @@ onShow(() => {
|
|||||||
uni.removeStorageSync('ACTIVITY_ACTIVE_TAB');
|
uni.removeStorageSync('ACTIVITY_ACTIVE_TAB');
|
||||||
}
|
}
|
||||||
fetchLiveActivities();
|
fetchLiveActivities();
|
||||||
|
fetchLiveCategories();
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
@@ -314,14 +340,26 @@ const filteredActivities = computed(() => {
|
|||||||
matchTab = a.payType === currentTab.value;
|
matchTab = a.payType === currentTab.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 品类筛选 (美食陪吃 / 同城陪唱 / 下午茶陪喝/微醺)
|
// 3. 品类筛选 (支持动态匹配后台下发品类)
|
||||||
let matchCat = true;
|
let matchCat = true;
|
||||||
if (currentCategory.value === 'MEAL') {
|
if (currentCategory.value && currentCategory.value !== 'ALL') {
|
||||||
matchCat = a.game === '美食陪吃';
|
const targetCatCode = currentCategory.value.toUpperCase();
|
||||||
} else if (currentCategory.value === 'SING') {
|
if (targetCatCode === 'MEAL') {
|
||||||
matchCat = a.game === '同城陪唱';
|
matchCat = a.game === '美食陪吃' || (a.gameCategory || '').includes('MEAL');
|
||||||
} else if (currentCategory.value === 'DRINK') {
|
} else if (targetCatCode === 'SING') {
|
||||||
matchCat = a.game === '下午茶陪喝' || a.game === '同城微醺';
|
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;
|
return matchKeyword && matchTab && matchCat;
|
||||||
});
|
});
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户