2026-08-09-dimension-recommendation-remove-design.md 6.5 KB

推荐组件移除维度参数设计

背景

推荐商品(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 / buildRecommendationReasondimensionCode 为 null 时无法计算维度分数 → 改为使用成员历史得分最低的维度作为"推荐维度"计算

父页面(11 个)

每个页面集成的改动:

  1. 去掉 dimensionCode prop 传参 → <DimensionProducts /> / <DimensionArticles /> / <DimensionActivities /> / <DimensionTasks />
  2. 去掉 loadDimensionProducts() / loadDimensionActivities() / loadDimensionTasks() 方法及对应的 API 调用
  3. 去掉不再需要的 import(getProductsByDomaingetActivityListgetTodayTasksByCategory 等)

涉及的页面列表:

页面文件 涉及的组件
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 返回全量
  • 非推荐相关组件(FamilyEnergyBarFamilyRelationGraph 等)

组件设计细节

DimensionProducts

// 移除 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

// 移除 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

// 移除 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

// 移除 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 为例:

- import { getEnergyOverview, getFamilyEnergySandbox, getTodayTasksByCategory, getActivityList, getProductsByDomain, getChildren } from '../../utils/api.js'
+ import { getEnergyOverview, getFamilyEnergySandbox, getChildren } from '../../utils/api.js'

  <template>
-   <DimensionTasks dimensionCode="body" ... />
+   <DimensionTasks ... />
-   <DimensionActivities dimensionCode="body" ... />
+   <DimensionActivities ... />
-   <DimensionProducts dimensionCode="body" ... />
+   <DimensionProducts ... />
  </template>

  // 去掉 loadDimensionTasks / loadDimensionActivities / loadDimensionProducts 方法

风险与注意事项

  • DimensionActivities 的维度图标去掉后,活动卡片的头部样式会变化,需确认是否影响视觉
  • DimensionProducts 自加载时不再传 dimensionCode,后端需处理空值返回全量
  • 所有父页面去掉本地数据加载后,组件自加载的数据是在 mounted 中触发