# 推荐组件移除维度参数设计 ## 背景 推荐商品(DimensionProducts)、推荐阅读(DimensionArticles)、推荐活动(DimensionActivities)、 推荐任务(DimensionTasks)四个组件当前都接收 `dimensionCode` 参数,接口按维度过滤推荐内容。 现改为不再区分维度,组件自加载全量推荐内容。 ## 改动范围 ### 组件(4 个) | 组件 | 当前行为 | 改为 | |------|---------|------| | `DimensionProducts.vue` | 接收 `dimensionCode` prop,传给 `/api/recommend/dimension-products` | 移除 dimensionCode prop,自加载时不传 dimensionCode,后端返回全量推荐 | | `DimensionArticles.vue` | 接收 `dimensionCode` prop(required 但未实际使用),数据由父页面传入 | 移除 dimensionCode prop,新增自加载 `getFeaturedArticles({ size: 3 })` | | `DimensionActivities.vue` | 接收 `dimensionCode` prop 用于显示维度图标,数据由父页面传入 | 移除 dimensionCode prop,固定图标为默认,新增自加载 `getActivityList({ page: 1, size: 3 })` | | `DimensionTasks.vue` | 接收 `dimensionCode` prop,传给 `getTodayTasksByCategory(memberId, category)` | 移除 dimensionCode prop,改为调用 `getTodayTasks(memberId)`(已存在该 API,不传 category 返回全部今日任务) | ### 后端(1 个) `ProductRecommendationController.getDimensionProducts()`: - 当前:`dimensionCode` 为空时返回错误 - 改为:`dimensionCode` 为空时,调用 `getDimensionRecommendations(null, ...)` 查询全量映射 `ProductRecommendationService.getDimensionRecommendations()`: - `dimensionCode` 为 null 时,查询所有 `dimension_mapping` 记录(去掉 `.eq(dimensionCode)` 条件),按 `matchScore` 排序返回 - 当前的 `applyDimensionBoost` / `calculateMatchScore` / `buildRecommendationReason` 在 `dimensionCode` 为 null 时无法计算维度分数 → 改为使用成员历史得分最低的维度作为"推荐维度"计算 ### 父页面(11 个) 每个页面集成的改动: 1. 去掉 `dimensionCode` prop 传参 → `` / `` / `` / `` 2. 去掉 `loadDimensionProducts()` / `loadDimensionActivities()` / `loadDimensionTasks()` 方法及对应的 API 调用 3. 去掉不再需要的 import(`getProductsByDomain`、`getActivityList`、`getTodayTasksByCategory` 等) 涉及的页面列表: | 页面文件 | 涉及的组件 | |---------|-----------| | `pages/body/member-body-detail.vue` | Products, Activities, Tasks | | `pages/mind/member-mind-detail.vue` | Products, Activities, Tasks | | `pages/wisdom/member-wisdom-detail.vue` | Products, Activities, Tasks | | `pages/action-detail/member-action-detail.vue` | Products, Activities, Tasks | | `pages/body-detail/member-body-detail.vue` | Products, Activities, Tasks | | `pages/mind-detail/member-mind-detail.vue` | Products, Activities, Tasks | | `pages/wisdom-detail/member-wisdom-detail.vue` | Products, Activities, Tasks | | `pages/index-home/index.vue` | Products, Articles, Activities | | `pages/member-detail/member-detail.vue` | Tasks | | `pages/home-pages/member-home-detail.vue` | Tasks | | `pages/growth-main/index.vue` | Activities | ### 不需要改动的 - `ArticleController` / `ArticleService` — 已支持空 `dimensionCode` 返回全量 - `ActivityController` / `ActivityService` — 已支持空 `dimensionCode` 返回全量 - `TaskController` / `TaskService` — 已支持空 `category`/`dimensionCode` 返回全量 - 非推荐相关组件(`FamilyEnergyBar`、`FamilyRelationGraph` 等) ## 组件设计细节 ### DimensionProducts ```vue // 移除 props: dimensionCode props: { products: { type: Array, default: () => [] }, // 保留,兼容模式 familyId: { type: [Number, String], default: null }, isLoggedIn: { type: Boolean, default: false }, title: { type: String, default: '推荐商品' }, showMore: { type: Boolean, default: true } } // loadDimensionProducts 改为不传 dimensionCode loadDimensionProducts: function() { getDimensionProducts({ limit: 4 }).then(...) } ``` ### DimensionArticles ```vue // 移除 props: dimensionCode(原 required 但未使用) props: { articles: { type: Array, default: () => [] }, isLoggedIn: { type: Boolean, default: false } } // 新增自加载 data: function() { return { selfArticles: [], loading: false } } mounted: function() { if (!this.articles || !this.articles.length) this.loadArticles() } methods: { loadArticles: function() { getFeaturedArticles({ size: 3 }).then(res => { ... }) } } ``` ### DimensionActivities ```vue // 移除 props: dimensionCode // 移除 dimensionIcon 相关逻辑(固定图标) props: { activities: { type: Array, default: () => [] }, isLoggedIn: { type: Boolean, default: false } } // 新增自加载 data: function() { return { selfActivities: [], loading: false, swiperIndex: 0 } } mounted: function() { if (!this.activities || !this.activities.length) this.loadActivities() } methods: { loadActivities: function() { getActivityList({ page: 1, size: 3 }).then(res => { ... }) } } ``` ### DimensionTasks ```vue // 移除 props: dimensionCode props: { tasks: { type: Array, default: () => [] }, memberId: { type: Number, default: null } } // 改为调用 getTodayTasks(不传 category,返回全部) loadTasks: function() { var self = this if (!self.memberId) return api.getTodayTasks(self.memberId).then(function(res) { self.tasksData = res.data || [] }).catch(function() {}) } ``` ## 父页面改动示例 以 `pages/body/member-body-detail.vue` 为例: ```diff - import { getEnergyOverview, getFamilyEnergySandbox, getTodayTasksByCategory, getActivityList, getProductsByDomain, getChildren } from '../../utils/api.js' + import { getEnergyOverview, getFamilyEnergySandbox, getChildren } from '../../utils/api.js' // 去掉 loadDimensionTasks / loadDimensionActivities / loadDimensionProducts 方法 ``` ## 风险与注意事项 - `DimensionActivities` 的维度图标去掉后,活动卡片的头部样式会变化,需确认是否影响视觉 - `DimensionProducts` 自加载时不再传 `dimensionCode`,后端需处理空值返回全量 - 所有父页面去掉本地数据加载后,组件自加载的数据是在 `mounted` 中触发