Sfoglia il codice sorgente

chore: auto bump version and changelog [skip ci]

iwt 2 mesi fa
parent
commit
8224f26cf7

+ 4 - 0
cfc-backend/src/main/java/com/etotem/cfc/entity/Article.java

@@ -1,6 +1,7 @@
 package com.etotem.cfc.entity;
 package com.etotem.cfc.entity;
 
 
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 import lombok.Data;
@@ -48,6 +49,9 @@ public class Article implements Serializable {
     private Integer isFeatured;
     private Integer isFeatured;
     private Date publishedAt;
     private Date publishedAt;
     private Integer viewCount;
     private Integer viewCount;
+    /** 总阅读时长(秒,瞬态字段,由 article_reading_records 聚合) */
+    @TableField(exist = false)
+    private Integer totalDurationSeconds;
     private Long createdBy;
     private Long createdBy;
     /** 作者类型: admin/parent/child */
     /** 作者类型: admin/parent/child */
     private String authorType;
     private String authorType;

+ 15 - 20
cfc-backend/src/main/java/com/etotem/cfc/mapper/ArticleReadingRecordMapper.java

@@ -19,37 +19,32 @@ public interface ArticleReadingRecordMapper extends BaseMapper<ArticleReadingRec
                                             @Param("since") java.util.Date since);
                                             @Param("since") java.util.Date since);
 
 
     /**
     /**
-     * 按文章 ID 分页查询阅读记录,JOIN family_members 获取昵称,按最后阅读时间倒序
+     * 按文章 ID 分页查询阅读记录(每人聚合一行),JOIN family_members 获取昵称
      */
      */
     @Select("SELECT " +
     @Select("SELECT " +
-            "  r.id, " +
-            "  r.user_id, " +
-            "  r.child_id, " +
-            "  r.duration_seconds, " +
-            "  r.read_at, " +
-            "  r.updated_at, " +
             "  m.nickname, " +
             "  m.nickname, " +
-            "  DATE(r.read_at) AS read_date " +
+            "  SUM(r.duration_seconds) AS total_duration_seconds, " +
+            "  COUNT(*) AS read_count, " +
+            "  MAX(r.updated_at) AS last_read_at, " +
+            "  MAX(DATE(r.read_at)) AS last_read_date " +
             "FROM article_reading_records r " +
             "FROM article_reading_records r " +
             "LEFT JOIN family_members m ON r.child_id = m.id " +
             "LEFT JOIN family_members m ON r.child_id = m.id " +
             "WHERE r.article_id = #{articleId} " +
             "WHERE r.article_id = #{articleId} " +
-            "ORDER BY r.updated_at DESC, r.read_at DESC " +
+            "GROUP BY r.child_id, m.nickname " +
+            "ORDER BY total_duration_seconds DESC " +
             "LIMIT #{limit} OFFSET #{offset}")
             "LIMIT #{limit} OFFSET #{offset}")
-    @Results(id = "readRecordResultMap", value = {
-            @Result(column = "id", property = "id"),
-            @Result(column = "user_id", property = "user_id"),
-            @Result(column = "child_id", property = "child_id"),
-            @Result(column = "duration_seconds", property = "duration_seconds"),
-            @Result(column = "read_at", property = "read_at"),
-            @Result(column = "updated_at", property = "updated_at"),
+    @Results(id = "readRecordAggregatedMap", value = {
             @Result(column = "nickname", property = "nickname"),
             @Result(column = "nickname", property = "nickname"),
-            @Result(column = "read_date", property = "read_date")
+            @Result(column = "total_duration_seconds", property = "total_duration_seconds"),
+            @Result(column = "read_count", property = "read_count"),
+            @Result(column = "last_read_at", property = "last_read_at"),
+            @Result(column = "last_read_date", property = "last_read_date")
     })
     })
-    List<Map<String, Object>> selectByArticle(
+    List<Map<String, Object>> selectByArticleAggregated(
             @Param("articleId") Long articleId,
             @Param("articleId") Long articleId,
             @Param("offset") int offset,
             @Param("offset") int offset,
             @Param("limit") int limit);
             @Param("limit") int limit);
 
 
-    @Select("SELECT COUNT(*) FROM article_reading_records WHERE article_id = #{articleId}")
-    long countByArticle(@Param("articleId") Long articleId);
+    @Select("SELECT COUNT(DISTINCT child_id) FROM article_reading_records WHERE article_id = #{articleId}")
+    long countDistinctByArticle(@Param("articleId") Long articleId);
 }
 }

+ 1 - 1
cfc-web/.last_build_commit

@@ -1 +1 @@
-d4ef373c2fc4b0b751673ea92e371f18e2f35172
+0a66391a1e09cb68f403bfdf8ee45cacc4ab2b34

+ 2 - 2
cfc-web/package-lock.json

@@ -1,12 +1,12 @@
 {
 {
   "name": "cfc-web",
   "name": "cfc-web",
-  "version": "1.0.1287",
+  "version": "1.0.1288",
   "lockfileVersion": 3,
   "lockfileVersion": 3,
   "requires": true,
   "requires": true,
   "packages": {
   "packages": {
     "": {
     "": {
       "name": "cfc-web",
       "name": "cfc-web",
-      "version": "1.0.1287",
+      "version": "1.0.1288",
       "dependencies": {
       "dependencies": {
         "@wangeditor/editor": "^5.1.23",
         "@wangeditor/editor": "^5.1.23",
         "@wangeditor/editor-for-vue": "^1.0.2",
         "@wangeditor/editor-for-vue": "^1.0.2",

+ 1 - 1
cfc-web/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "cfc-web",
   "name": "cfc-web",
-  "version": "1.0.1288",
+  "version": "1.0.1289",
   "private": true,
   "private": true,
   "scripts": {
   "scripts": {
     "dev": "vue-cli-service serve",
     "dev": "vue-cli-service serve",

+ 35 - 0
cfc-web/public/CHANGELOG-v1.0.md

@@ -4,6 +4,41 @@
 
 
 ---
 ---
 
 
+## v1.0.1289 (2026-09-03)
+
+### Bug 修复
+- processGifts 下单时复核赠品商品库存
+- 修复 toggleGift 后多余逗号语法错误
+- class 改用 _selected 状态字段,移除方法调用
+
+### 新功能
+- 管理端商品编辑页新增可选赠品配置区块
+- 小程序商品详情赠品选择区 + checkout 透传 giftItemIds
+- createMultiItem 单商品路径支持赠品(抽取 processGifts 共享方法)
+- handlePaymentSuccess 追加赠品发放逻辑
+- create 流程注入赠品校验与 product_order_gifts 记录
+- 新增管理端赠品配置接口(/api/admin/product-gift/save + /list)
+- 新增 ProductGiftService(配置保存/查询逻辑)
+- 新增三张赠品表实体类与Mapper接口
+- 建三张赠品相关表迁移(product_gift_configs/items/order_gifts)
+
+### 其他
+- feat(product-gift): 商品详情附带当前用户等级赠品配置
+- - 涵盖:数据库迁移、实体/Mapper、ProductGiftService、管理端接口、
+-   下单校验+写记录、支付成功发放、商品详情装配、小程序前端、管理端前端
+- 
+-   - 3张新表:product_gift_configs / product_gift_items / product_order_gifts
+-   - 与现有 product_gift_rules(赠送会员)完全独立
+-   - 赠品类型:商品 或 CF值,按会员等级配置,用户可多选
+-   - 下单时写入订单赠品记录(fulfilled=0),支付成功后发放
+- - 更新 PROJECT-OVERVIEW.md §4.2 电商与供应体系,记录新设计稿
+- 
+
+### 文档
+- 商品可选赠品功能实施计划
+- 商品可选赠品功能设计稿(product-gift-selection-design)
+
+
 ## v1.0.1288 (2026-09-03)
 ## v1.0.1288 (2026-09-03)
 
 
 ### Bug 修复
 ### Bug 修复

+ 36 - 1
cfc-web/public/CHANGELOG.md

@@ -1,6 +1,6 @@
 # 更新日志
 # 更新日志
 
 
-> 当前版本: v1.0.1288
+> 当前版本: v1.0.1289
 
 
 ## 历史版本
 ## 历史版本
 
 
@@ -8,6 +8,41 @@
 
 
 ---
 ---
 
 
+## v1.0.1289 (2026-09-03)
+
+### Bug 修复
+- processGifts 下单时复核赠品商品库存
+- 修复 toggleGift 后多余逗号语法错误
+- class 改用 _selected 状态字段,移除方法调用
+
+### 新功能
+- 管理端商品编辑页新增可选赠品配置区块
+- 小程序商品详情赠品选择区 + checkout 透传 giftItemIds
+- createMultiItem 单商品路径支持赠品(抽取 processGifts 共享方法)
+- handlePaymentSuccess 追加赠品发放逻辑
+- create 流程注入赠品校验与 product_order_gifts 记录
+- 新增管理端赠品配置接口(/api/admin/product-gift/save + /list)
+- 新增 ProductGiftService(配置保存/查询逻辑)
+- 新增三张赠品表实体类与Mapper接口
+- 建三张赠品相关表迁移(product_gift_configs/items/order_gifts)
+
+### 其他
+- feat(product-gift): 商品详情附带当前用户等级赠品配置
+- - 涵盖:数据库迁移、实体/Mapper、ProductGiftService、管理端接口、
+-   下单校验+写记录、支付成功发放、商品详情装配、小程序前端、管理端前端
+- 
+-   - 3张新表:product_gift_configs / product_gift_items / product_order_gifts
+-   - 与现有 product_gift_rules(赠送会员)完全独立
+-   - 赠品类型:商品 或 CF值,按会员等级配置,用户可多选
+-   - 下单时写入订单赠品记录(fulfilled=0),支付成功后发放
+- - 更新 PROJECT-OVERVIEW.md §4.2 电商与供应体系,记录新设计稿
+- 
+
+### 文档
+- 商品可选赠品功能实施计划
+- 商品可选赠品功能设计稿(product-gift-selection-design)
+
+
 ## v1.0.1288 (2026-09-03)
 ## v1.0.1288 (2026-09-03)
 
 
 ### Bug 修复
 ### Bug 修复