|
@@ -0,0 +1,162 @@
|
|
|
|
|
+# 维度参数获取与筛选设计分析
|
|
|
|
|
+
|
|
|
|
|
+## 概述
|
|
|
|
|
+
|
|
|
|
|
+四个核心实体(活动、商品、文章、任务)都有"五维归属"的概念,但存储和查询方式各不相同。当前设计目标是:**根据维度筛选时,只要该实体在对应维度的权重 > 0 就命中**。
|
|
|
|
|
+
|
|
|
|
|
+## 实体维度字段对比
|
|
|
|
|
+
|
|
|
|
|
+| 实体 | 表名 | 旧字段 | 新字段 | 维度筛选方式 |
|
|
|
|
|
+|------|------|--------|--------|-------------|
|
|
|
|
|
+| **Activity** | activities | `dimension_code` (单值) | `dimension_weights` (JSON) | `JSON_EXTRACT(dimension_weights, '$.{dim}') > 0` OR `dimension_code = {dim}` |
|
|
|
|
|
+| **Product** | products | `domain` (单值) | `dimension_weights` (JSON) | `JSON_EXTRACT(dimension_weights, '$.{dim}') > 0` OR `domain = {dim}` |
|
|
|
|
|
+| **Article** | articles | `related_dimensions` (逗号分隔) | `dimension_weights` (JSON) | `JSON_EXTRACT(dimension_weights, '$.{dim}') > 0` OR `related_dimensions LIKE %{dim}%` |
|
|
|
|
|
+| **Task** | tasks | 无 | 无 | ❌ 不支持维度筛选 |
|
|
|
|
|
+
|
|
|
|
|
+## 逐项分析
|
|
|
|
|
+
|
|
|
|
|
+### 1. Activity(活动)✅ 已实现
|
|
|
|
|
+
|
|
|
|
|
+**实体字段:**
|
|
|
|
|
+```java
|
|
|
|
|
+private String dimensionCode; // 旧: 单值, 如 "body"
|
|
|
|
|
+private String dimensionWeights; // 新: JSON, 如 {"body":30,"mind":0,"wisdom":0,"action":70,"wealth":0}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**筛选逻辑(ActivityService.list() 第53-63行):**
|
|
|
|
|
+```java
|
|
|
|
|
+if (dimensionCode != null && !dimensionCode.isEmpty()) {
|
|
|
|
|
+ query.and(w -> w
|
|
|
|
|
+ .apply("COALESCE(JSON_EXTRACT(dimension_weights, '$." + dimensionCode + "'), 0) > 0")
|
|
|
|
|
+ .or().eq(Activity::getDimensionCode, dimensionCode)
|
|
|
|
|
+ );
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**状态:** ✅ 已实现权重感知筛选,兼容旧版 `dimensionCode`
|
|
|
|
|
+
|
|
|
|
|
+### 2. Product(商品)✅ 已实现
|
|
|
|
|
+
|
|
|
|
|
+**实体字段:**
|
|
|
|
|
+```java
|
|
|
|
|
+private String domain; // 旧: 单值, 如 "body"
|
|
|
|
|
+private String dimensionWeights; // 新: JSON, 如 {"body":30,"mind":0,"wisdom":0,"action":70,"wealth":0}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**筛选逻辑(ProductService.list() 第56-62行):**
|
|
|
|
|
+```java
|
|
|
|
|
+if (query.getDomain() != null && !query.getDomain().isEmpty()) {
|
|
|
|
|
+ String domain = query.getDomain();
|
|
|
|
|
+ wrapper.and(w -> w
|
|
|
|
|
+ .apply("COALESCE(JSON_EXTRACT(dimension_weights, '$." + domain + "'), 0) > 0")
|
|
|
|
|
+ .or().eq(Product::getDomain, domain)
|
|
|
|
|
+ );
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**注意:** 查询参数名为 `domain`(ProductListQueryDTO 中定义),前端传的是 `dimensionCode` 还是 `domain` 需要确认对齐。
|
|
|
|
|
+
|
|
|
|
|
+**状态:** ✅ 已实现权重感知筛选,兼容旧版 `domain`
|
|
|
|
|
+
|
|
|
|
|
+### 3. Article(文章)✅ 已实现
|
|
|
|
|
+
|
|
|
|
|
+**实体字段:**
|
|
|
|
|
+```java
|
|
|
|
|
+private String relatedDimensions; // 旧: 逗号分隔, 如 "body,mind"
|
|
|
|
|
+private String dimensionIds; // 维度ID列表JSON
|
|
|
|
|
+private String dimensionWeights; // 新: JSON, 如 {"body":30,"mind":0,...}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**筛选逻辑(ArticleService.getPublicList() 第93-98行):**
|
|
|
|
|
+```java
|
|
|
|
|
+if (dimensionCode != null && !dimensionCode.trim().isEmpty()) {
|
|
|
|
|
+ wrapper.and(w -> w
|
|
|
|
|
+ .apply("COALESCE(JSON_EXTRACT(dimension_weights, '$." + dimensionCode.trim() + "'), 0) > 0")
|
|
|
|
|
+ .or().like(Article::getRelatedDimensions, dimensionCode.trim())
|
|
|
|
|
+ );
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**自动生成权重的逻辑(ArticleService 第702-706行):**
|
|
|
|
|
+当管理员设置 `relatedDimensions` 时,自动调用 `buildEqualWeights()` 生成等比例权重:
|
|
|
|
|
+```java
|
|
|
|
|
+private String buildEqualWeights(String relatedDimensions) {
|
|
|
|
|
+ String[] parts = relatedDimensions.split(",");
|
|
|
|
|
+ int equalWeight = 100 / parts.length;
|
|
|
|
|
+ // 为每个维度分配 equalWeight
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**状态:** ✅ 已实现权重感知筛选,兼容旧版 `relatedDimensions`
|
|
|
|
|
+
|
|
|
|
|
+### 4. Task(任务)❌ 不支持维度筛选
|
|
|
|
|
+
|
|
|
|
|
+**实体字段:** 无维度相关字段
|
|
|
|
|
+
|
|
|
|
|
+Task 实体没有 `dimensionCode`、`domain`、`dimensionWeights` 等任何维度字段。任务通过 `category` 字段分类(如"学习类""行动类"),但分类与五维维度没有直接映射关系。
|
|
|
|
|
+
|
|
|
|
|
+**状态:** ❌ 不支持维度筛选
|
|
|
|
|
+
|
|
|
|
|
+## 架构设计
|
|
|
|
|
+
|
|
|
|
|
+### JSON 权重格式
|
|
|
|
|
+
|
|
|
|
|
+所有实体统一使用 JSON 格式存储五维权重:
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "body": 0,
|
|
|
|
|
+ "mind": 30,
|
|
|
|
|
+ "wisdom": 20,
|
|
|
|
|
+ "action": 50,
|
|
|
|
|
+ "wealth": 0
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+- 权重值范围:0-100(整数)
|
|
|
|
|
+- 0 = 不关联该维度
|
|
|
|
|
+- > 0 = 关联该维度,值越大关联度越高
|
|
|
|
|
+- 所有权重之和不一定等于 100(可以只设置部分维度)
|
|
|
|
|
+
|
|
|
|
|
+### 筛选原理
|
|
|
|
|
+
|
|
|
|
|
+使用 MySQL 的 `JSON_EXTRACT` 函数:
|
|
|
|
|
+```sql
|
|
|
|
|
+COALESCE(JSON_EXTRACT(dimension_weights, '$.body'), 0) > 0
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+- 如果 `dimension_weights` 为 NULL 或 JSON 中不含该 key,返回 0
|
|
|
|
|
+- 如果权重 > 0,表示该实体关联此维度,命中筛选
|
|
|
|
|
+
|
|
|
|
|
+### 兼容旧数据
|
|
|
|
|
+
|
|
|
|
|
+三种实体都保留了旧字段的兼容查询:
|
|
|
|
|
+- Activity: `dimension_code` 精确匹配
|
|
|
|
|
+- Product: `domain` 精确匹配
|
|
|
|
|
+- Article: `related_dimensions` LIKE 模糊匹配
|
|
|
|
|
+
|
|
|
|
|
+## 前端调用方式
|
|
|
|
|
+
|
|
|
|
|
+| 实体 | 列表接口 | 维度参数名 | 示例 |
|
|
|
|
|
+|------|---------|-----------|------|
|
|
|
|
|
+| 活动 | `POST /api/activity/list` | `dimensionCode` | `{"dimensionCode":"body"}` |
|
|
|
|
|
+| 商品 | `POST /api/product/list` | `domain` | `{"domain":"body"}` |
|
|
|
|
|
+| 文章 | `POST /api/articles/list` | `dimensionCode` | `{"dimensionCode":"body"}` |
|
|
|
|
|
+| 任务 | `POST /api/tasks/today` | 不支持 | — |
|
|
|
|
|
+
|
|
|
|
|
+## 建议
|
|
|
|
|
+
|
|
|
|
|
+### 统一参数名
|
|
|
|
|
+商品列表使用 `domain` 而非 `dimensionCode`,与其他三个不统一。建议在 `ProductListQueryDTO` 中增加 `dimensionCode` 别名,内部映射到 `domain`。
|
|
|
|
|
+
|
|
|
|
|
+### Task 增加维度支持
|
|
|
|
|
+如果任务需要按维度筛选,有两种方案:
|
|
|
|
|
+1. **轻量方案**:在 Task 实体增加 `dimensionCode` 字段(单值),通过 `category` → `dimensionCode` 映射表自动填充
|
|
|
|
|
+2. **完整方案**:增加 `dimensionWeights` JSON 字段,与活动/商品/文章保持一致
|
|
|
|
|
+
|
|
|
|
|
+### 创建/编辑时的维度设置
|
|
|
|
|
+| 实体 | 创建接口 | 维度参数 | 说明 |
|
|
|
|
|
+|------|---------|---------|------|
|
|
|
|
|
+| 活动 | `POST /api/admin/activity/create` | `dimensionCode` + `dimensionWeights` | 管理后台设置 |
|
|
|
|
|
+| 商品 | `POST /api/product/create` | `domain` + `dimensionWeights` | 管理后台设置 |
|
|
|
|
|
+| 文章 | `POST /api/admin/articles/create` | `relatedDimensions` | 自动生成 `dimensionWeights` |
|
|
|
|
|
+| 任务 | `POST /api/tasks/create` | 不支持 | 通过 category 间接关联 |
|