feat(nav-category): support dynamic home grid categories in admin and uniapp

这个提交包含在:
xcbyy
2026-10-10 09:08:18 +08:00
父节点 f010cfb7ab
当前提交 51682fffea
共有 11 个文件被更改,包括 1077 次插入 和 6 次删除

查看文件

@@ -564,6 +564,21 @@ export async function getBanners() {
return null;
}
/**
* 获取首页金刚区活动品类导航列表 (配置化接口)
*/
export async function getNavCategories() {
try {
const res = await http.get('/nav-categories');
if (Array.isArray(res) && res.length > 0) {
return res;
}
} catch (err) {
console.warn('[API] 获取金刚区品类导航异常:', err.message);
}
return null;
}

查看文件

@@ -29,18 +29,19 @@
</swiper>
<!-- 陪玩活动项目专属金刚区 (10宫格经典网格:2行×5列,纯图标+主标题) -->
<!-- 陪玩活动项目专属金刚区 (动态活动品类导航网格:纯图标+主标题+高亮角标) -->
<view class="quick-grid grid-card">
<view
v-for="item in activityProjects"
:key="item.id"
v-for="item in navCategories"
:key="item.id || item.code"
class="quick-item btn-active"
@click="handleProjectClick(item)"
>
<view class="quick-icon-bg" :class="item.bgClass">
<image class="quick-svg" :src="item.icon" mode="aspectFit" />
<image class="quick-svg" :src="resolveIcon(item.icon)" mode="aspectFit" />
</view>
<text class="quick-title">{{ item.name }}</text>
<text v-if="item.badgeText" class="quick-badge">{{ item.badgeText }}</text>
</view>
</view>
@@ -128,7 +129,7 @@ import { onShow } from '@dcloudio/uni-app';
import CustomTabBar from '@/components/CustomTabBar.vue';
import SkeletonScreen from '@/components/SkeletonScreen.vue';
import PrivacyModal from '@/components/PrivacyModal.vue';
import { getCompanions, getBanners } from '@/common/api.js';
import { getCompanions, getBanners, getNavCategories } from '@/common/api.js';
import { ICONS } from '@/common/icons.js';
import { getCurrentThemeKey, applyThemeToNativeUI } from '@/common/theme.js';
import { getNavBarInfo } from '@/common/nav.js';
@@ -136,6 +137,7 @@ import { getNavBarInfo } from '@/common/nav.js';
const isLoading = ref(true);
const banners = ref([]);
const experts = ref([]);
const navCategories = ref([]);
const currentCategory = ref('all');
const playingId = ref(null);
const currentThemeKey = ref(getCurrentThemeKey());
@@ -153,7 +155,8 @@ const loadInitialData = async () => {
try {
await Promise.allSettled([
fetchLiveCompanions(),
fetchLiveBanners()
fetchLiveBanners(),
fetchLiveNavCategories()
]);
} finally {
// 平滑延时关闭骨架屏,呈现优雅扫光转场
@@ -185,6 +188,23 @@ const fetchLiveBanners = async () => {
}
};
const fetchLiveNavCategories = async () => {
try {
const list = await getNavCategories();
if (Array.isArray(list) && list.length > 0) {
navCategories.value = list;
}
} catch (err) {
console.warn('[Index] 获取金刚区品类导航失败:', err);
}
};
const resolveIcon = (icon) => {
if (!icon) return ICONS.gridAll;
if (ICONS[icon]) return ICONS[icon];
return icon;
};
const onThemeChanged = (key) => {
currentThemeKey.value = key;
applyThemeToNativeUI(key);
@@ -205,6 +225,7 @@ onShow(() => {
uni.hideTabBar({ animation: false, fail: () => {} });
fetchLiveCompanions();
fetchLiveBanners();
fetchLiveNavCategories();
});
@@ -543,6 +564,22 @@ const navTo = (url) => {
line-height: 1.2;
}
.quick-badge {
position: absolute;
top: -6rpx;
right: 6rpx;
background: linear-gradient(135deg, #F43F5E 0%, #FB7185 100%);
color: #FFFFFF;
font-size: 16rpx;
padding: 2rpx 8rpx;
border-radius: 12rpx;
font-weight: 700;
box-shadow: 0 2rpx 6rpx rgba(244, 63, 94, 0.4);
transform: scale(0.9);
}
position: relative;
&:active .quick-icon-bg {
transform: scale(0.92);
}