|
@@ -0,0 +1,160 @@
|
|
|
|
|
+# 推荐组件移除维度参数设计
|
|
|
|
|
+
|
|
|
|
|
+## 背景
|
|
|
|
|
+
|
|
|
|
|
+推荐商品(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)`(不传 category) |
|
|
|
|
|
+
|
|
|
|
|
+### 后端(1 个)
|
|
|
|
|
+
|
|
|
|
|
+`ProductRecommendationController.getDimensionProducts()`:
|
|
|
|
|
+- 当前:`dimensionCode` 为空时返回错误
|
|
|
|
|
+- 改为:`dimensionCode` 为空时,调用 `getDimensionRecommendations(null, ...)` 查询全量映射
|
|
|
|
|
+
|
|
|
|
|
+`ProductRecommendationService.getDimensionRecommendations()`:
|
|
|
|
|
+- `dimensionCode` 为 null 时,查询所有 `dimension_mapping` 记录(去掉 `.eq(dimensionCode)` 条件)
|
|
|
|
|
+
|
|
|
|
|
+### 父页面(11 个)
|
|
|
|
|
+
|
|
|
|
|
+每个页面集成的改动:
|
|
|
|
|
+
|
|
|
|
|
+1. 去掉 `dimensionCode` prop 传参 → `<DimensionProducts />` / `<DimensionArticles />` / `<DimensionActivities />` / `<DimensionTasks />`
|
|
|
|
|
+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 }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 改为不传 category
|
|
|
|
|
+loadTasks: function() {
|
|
|
|
|
+ if (!this.memberId) return
|
|
|
|
|
+ api.getTodayTasks({ memberId: self.memberId }).then(...)
|
|
|
|
|
+ // 或者直接调用 getTodayTasksByCategory(memberId, null)
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 父页面改动示例
|
|
|
|
|
+
|
|
|
|
|
+以 `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'
|
|
|
|
|
+
|
|
|
|
|
+ <template>
|
|
|
|
|
+- <DimensionTasks dimensionCode="body" ... />
|
|
|
|
|
++ <DimensionTasks ... />
|
|
|
|
|
+- <DimensionActivities dimensionCode="body" ... />
|
|
|
|
|
++ <DimensionActivities ... />
|
|
|
|
|
+- <DimensionProducts dimensionCode="body" ... />
|
|
|
|
|
++ <DimensionProducts ... />
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ // 去掉 loadDimensionTasks / loadDimensionActivities / loadDimensionProducts 方法
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 风险与注意事项
|
|
|
|
|
+
|
|
|
|
|
+- `DimensionActivities` 的维度图标去掉后,活动卡片的头部样式会变化,需确认是否影响视觉
|
|
|
|
|
+- `DimensionProducts` 自加载时不再传 `dimensionCode`,后端需处理空值返回全量
|
|
|
|
|
+- 所有父页面去掉本地数据加载后,组件自加载的数据是在 `mounted` 中触发
|