hookehuyr

feat(index): 首页网格导航动态化,支持后台配置

## 主要变更

### 优化
- 移除硬编码的 CATEGORY_IDS 和 loopNav 配置
- 新增 fetchHomeIcons 函数,从 API 动态获取导航数据
- 实现智能参数解析,自动提取 link 字段中的路由和查询参数
- 支持任意数量的查询参数(如 cid, category_id 等)
- API 失败时自动降级到默认配置,保证可用性

### 导航跳转逻辑优化
- 重构 handleGridNav 函数,使用通用的参数提取逻辑
- 自动添加 title 参数到目标页面
- 移除硬编码的路由判断,提升可维护性

### 代码质量提升
- 性能优化:使用 shallowRef 存储导航数据
- 错误处理:完善的 try-catch 和降级方案
- 代码注释:添加完整的 JSDoc 注释

## 影响文件
- src/pages/index/index.vue
- docs/CHANGELOG.md

## 技术细节
- link 字段格式:/pages/category-list/index?cid=3129684
- 自动解析路由和查询参数
- 参数值自动 URL 解码
- 灵活支持后台配置,无需发版

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
......@@ -5,6 +5,33 @@
---
## [2026-02-05] - 首页网格导航动态化
### 优化
- **首页网格导航** (`src/pages/index/index.vue`)
- 移除硬编码的 `CATEGORY_IDS` 配置和 `loopNav` 数组
- 新增 `fetchHomeIcons` 函数,从 API 动态获取导航数据
- 实现智能参数解析,自动提取 `link` 字段中的路由和查询参数
- 支持任意数量的查询参数 (如 `cid`, `category_id` 等)
- API 失败时自动降级到默认配置,保证可用性
- **导航跳转逻辑优化**
- 重构 `handleGridNav` 函数,使用通用的参数提取逻辑
- 自动添加 `title` 参数到目标页面
- 移除硬编码的路由判断,提升可维护性
### 代码质量提升
- **性能优化**: 使用 `shallowRef` 存储导航数据,避免深度响应式
- **错误处理**: 完善的 try-catch 和降级方案
- **代码注释**: 添加完整的 JSDoc 注释
- **可维护性**: 支持后台配置,无需修改代码即可调整导航
### 影响
- **灵活性**: 可通过后台接口动态配置首页导航,无需发版
- **可扩展性**: 支持任意数量的查询参数
- **稳定性**: API 失败时有降级方案,不影响核心功能
---
## [2026-02-05] - 代码重构:收藏操作逻辑抽取
### 重构
......
......@@ -191,6 +191,7 @@ import ListItemActions from '@/components/ListItemActions/index.vue';
import { listAPI } from '@/api/get_product';
import { weekHotAPI } from '@/api/file';
import { useCollectOperation } from '@/composables/useCollectOperation';
import { homeIconAPI } from '@/api/home';
// User Store
const userStore = useUserStore();
......@@ -223,25 +224,55 @@ const handlePlanSubmit = (formData) => {
};
/**
* 分类 ID 配置
* @description 各业务模块对应的分类 ID,需要根据后端实际返回的 ID 配置
* TODO: 将这些 CID 替换为实际的分类 ID
* 首页网格导航数据
*
* @description 从 API 动态获取,包含图标、名称、路由等信息
*/
const CATEGORY_IDS = {
onboarding: '3129684', // 入职相关分类 ID
signing: '', // 签单相关分类 ID
familyOffice: '', // 家办相关分类 ID
customerService: '' // 客户服务分类 ID
}
const loopNav = shallowRef([]);
/**
* 获取首页图标列表
*
* @description 从 API 获取首页网格导航数据,并解析 link 字段
*/
const fetchHomeIcons = async () => {
try {
const res = await homeIconAPI();
if (res.code === 1 && res.data) {
// 将 API 数据映射为 loopNav 格式
loopNav.value = res.data.map(item => {
// 解析 link 字段,格式: "/pages/category-list/index?cid=3129684"
const [route, queryStr] = item.link.split('?');
const params = {};
// 如果有查询参数,解析为对象
if (queryStr) {
queryStr.split('&').forEach(param => {
const [key, value] = param.split('=');
params[key] = decodeURIComponent(value);
});
}
const loopNav = shallowRef([
// 返回导航项对象
return {
id: String(item.id),
icon: item.icon,
name: item.name,
route,
...params // 展开参数(如 cid)
};
});
}
} catch (err) {
console.error('获取首页图标失败:', err);
// 如果 API 调用失败,使用默认配置
loopNav.value = [
{ id: 'plan', icon: 'order', name: '计划书', route: '/pages/plan/index' },
{ id: 'onboarding', icon: 'my', name: '入职相关', route: '/pages/category-list/index', cid: CATEGORY_IDS.onboarding },
{ id: 'signing', icon: 'cart', name: '签单相关', route: '/pages/category-list/index', cid: CATEGORY_IDS.signing },
{ id: 'family-office', icon: 'home', name: '家办相关', route: '/pages/category-list/index', cid: CATEGORY_IDS.familyOffice },
{ id: 'knowledge-base', icon: 'category', name: '产品知识库', route: '/pages/knowledge-base/index' },
{ id: 'customer-service', icon: 'star', name: '客户服务', route: '/pages/category-list/index', cid: CATEGORY_IDS.customerService },
]);
{ id: 'knowledge-base', icon: 'category', name: '产品知识库', route: '/pages/knowledge-base/index' }
];
}
};
/**
* 热卖产品数据
......@@ -337,7 +368,15 @@ const { handleClick: onViewMaterial } = useListItemClick({
// 使用收藏操作 composable
const { toggleCollect: toggleMaterialCollect } = useCollectOperation();
// Handle grid navigation click
/**
* 处理网格导航点击
*
* @description 根据导航项的路由和参数进行跳转
* @param {Object} item - 导航项对象
* @param {string} item.route - 目标路由
* @param {string} item.name - 导航名称
* @param {Object} [item.cid] - 可选的分类 ID 参数
*/
const handleGridNav = (item) => {
if (!item.route) {
Taro.showToast({
......@@ -348,14 +387,21 @@ const handleGridNav = (item) => {
return;
}
// 如果是分类列表页面,需要带参数跳转
if (item.route === '/pages/category-list/index') {
// 提取除 route 以外的所有参数(如 cid)
const params = { ...item };
delete params.id;
delete params.icon;
delete params.name;
delete params.route;
// 如果有参数(如 cid),则带参数跳转
if (Object.keys(params).length > 0) {
go(item.route, {
cid: item.cid, // 分类 ID
title: item.name // 页面标题
...params,
title: item.name // 将导航名称作为页面标题
});
} else {
// 其他页面直接跳转
// 无参数,直接跳转
go(item.route);
}
};
......@@ -374,8 +420,9 @@ const openWebView = (url) => {
});
};
// 页面加载时获取热卖产品和热门资料
// 页面加载时获取首页图标、热卖产品和热门资料
useLoad(() => {
fetchHomeIcons();
fetchHotProducts();
fetchHotMaterials();
});
......