Parcourir la source

chore: auto bump version and changelog [skip ci]

iwt il y a 1 semaine
Parent
commit
7530d6f878

+ 3 - 0
cfc-backend/src/main/java/com/etotem/cfc/controller/HealthExerciseController.java

@@ -45,6 +45,9 @@ public class HealthExerciseController {
         if (record.getMemberId() == null) {
             record.setMemberId(currentMemberId);
         }
+        if (record.getMemberId() == null) return Result.error("memberId不能为空");
+        if (record.getExerciseType() == null || record.getExerciseType().trim().isEmpty()) return Result.error("请选择运动类型");
+        if (record.getDurationMinutes() == null || record.getDurationMinutes() <= 0) return Result.error("运动时长需大于0分钟");
         record.setCreatedAt(new Date());
         healthExerciseRecordMapper.insert(record);
                 // 触发画像重算

+ 8 - 1
cfc-backend/src/main/java/com/etotem/cfc/controller/HealthMealController.java

@@ -45,7 +45,14 @@ public class HealthMealController {
 
     @Operation(summary = "创建饮食打卡")
     @PostMapping("/create")
-    public Result<HealthMealRecord> create(@RequestBody HealthMealRecord record) {
+    public Result<HealthMealRecord> create(@RequestBody HealthMealRecord record,
+                                           @RequestAttribute(value = "currentMemberId", required = false) Long currentMemberId) {
+        if (record.getMemberId() == null) {
+            record.setMemberId(currentMemberId);
+        }
+        if (record.getMemberId() == null) return Result.error("memberId不能为空");
+        if (record.getMealType() == null || record.getMealType().trim().isEmpty()) return Result.error("请选择餐次");
+        if (record.getFoodItems() == null || record.getFoodItems().trim().isEmpty()) return Result.error("请填写食物清单");
         record.setCreatedAt(new Date());
         healthMealRecordMapper.insert(record);
         // 饮食打卡返积分:每次记录奖励 5 积分(不影响打卡主流程)

+ 3 - 0
cfc-backend/src/main/java/com/etotem/cfc/controller/HealthSleepController.java

@@ -45,6 +45,9 @@ public class HealthSleepController {
         if (record.getMemberId() == null) {
             record.setMemberId(currentMemberId);
         }
+        if (record.getMemberId() == null) return Result.error("memberId不能为空");
+        if (record.getSleepTime() == null) return Result.error("请选择入睡时间");
+        if (record.getWakeTime() == null) return Result.error("请选择醒来时间");
         record.setCreatedAt(new Date());
         healthSleepRecordMapper.insert(record);
                 // 触发画像重算

+ 1 - 1
cfc-backend/src/main/java/com/etotem/cfc/controller/InviteController.java

@@ -66,7 +66,7 @@ public class InviteController {
     public Result<Map<String, Object>> getQrCode(@RequestAttribute("userId") Long userId) {
         try {
             String referralCode = commissionService.getOrCreateReferralCode(userId);
-            String qrBase64 = wechatService.generateWxacode(referralCode, "pages/invite/join");
+            String qrBase64 = wechatService.generateWxacode("ref=" + referralCode, "pages/invite/join");
             Map<String, Object> result = new HashMap<>();
             result.put("qrCodeBase64", "data:image/png;base64," + qrBase64);
             result.put("referralCode", referralCode);

+ 3 - 0
cfc-backend/src/main/java/com/etotem/cfc/service/EmotionCheckinService.java

@@ -49,6 +49,9 @@ public class EmotionCheckinService {
         if (child == null) {
             throw new RuntimeException("孩子不存在");
         }
+        if (dto.getEmotionType() == null || dto.getEmotionType().trim().isEmpty()) {
+            throw new RuntimeException("请选择情绪类型");
+        }
 
         EmotionCheckin checkin = new EmotionCheckin();
         checkin.setChildId(dto.getMemberId());

+ 5 - 1
cfc-frontend/App.vue

@@ -10,7 +10,11 @@ export default {
     // 捕获分享/邀请参数(普通分享链接 ?inviteCode=xxx):未登录写入 storage 供注册登录后绑定推荐人,已登录直接绑定
     this.captureReferralParams(options)
     // 分享/深链冷启动(携带分享参数)放行到落地页,不套 splash,避免分享的文章/小程序页面打不开
-    var hasDeepLink = options && options.query && (options.query.inviteCode || options.query.id)
+    // inviteCode=推荐码(文章/活动/商品分享)| refCode=推广码 | token/familyInviteCode=家庭邀请令牌 | id=内容详情
+    var hasDeepLink = options && options.query && (
+      options.query.inviteCode || options.query.refCode || options.query.token ||
+      options.query.familyInviteCode || options.query.id
+    )
     // 冷启动:跳转到 splash 页展示过渡动画,2秒后自动进入首页
     if (options.scene !== 1047 && options.scene !== 1048 && options.scene !== 1049 && !hasDeepLink) {
       uni.setStorageSync('_isFirstLaunch', '1')

+ 1 - 0
cfc-frontend/pages/growth/diet-checkin.vue

@@ -298,6 +298,7 @@ export default {
     async doCheckin() {
       var self = this
       if (!self.form.mealType) { uni.showToast({ title: '请选择餐次', icon: 'none' }); return }
+      if (!self.form.foodItems || !self.form.foodItems.trim()) { uni.showToast({ title: '请填写食物清单', icon: 'none' }); return }
       if (!self.memberId) { uni.showToast({ title: '孩子ID无效', icon: 'none' }); return }
       self.submitting = true
       try {

+ 2 - 1
cfc-frontend/pages/growth/exercise-checkin.vue

@@ -311,7 +311,8 @@ export default {
     async doCheckin() {
       var self = this
       if (!self.form.exerciseType) { uni.showToast({ title: '请选择运动类型', icon: 'none' }); return }
-      if (!self.form.durationMinutes) { uni.showToast({ title: '请填写运动时长', icon: 'none' }); return }
+      var durationNum = parseInt(self.form.durationMinutes)
+      if (!self.form.durationMinutes || isNaN(durationNum) || durationNum <= 0) { uni.showToast({ title: '请填写有效的运动时长', icon: 'none' }); return }
       if (!self.memberId) { uni.showToast({ title: '孩子ID无效', icon: 'none' }); return }
       self.submitting = true
       try {

+ 1 - 0
cfc-frontend/pages/growth/growth-emotion-checkin.vue

@@ -280,6 +280,7 @@ export default {
     },
     async doCheckin() {
       var self = this
+      if (!self.selectedEmotion) { uni.showToast({ title: '请选择当前心情', icon: 'none' }); return }
       if (!self.memberId) { uni.showToast({ title: '孩子ID无效', icon: 'none' }); return }
       self.submitting = true
       try {

+ 1 - 0
cfc-frontend/pages/growth/sleep-checkin.vue

@@ -143,6 +143,7 @@ export default {
       var self = this
       if (!self.form.sleepTime) { uni.showToast({ title: '请选择入睡时间', icon: 'none' }); return }
       if (!self.form.wakeTime) { uni.showToast({ title: '请选择醒来时间', icon: 'none' }); return }
+      if (self.form.sleepTime === self.form.wakeTime) { uni.showToast({ title: '入睡和醒来时间不能相同', icon: 'none' }); return }
       if (!self.memberId) { uni.showToast({ title: '孩子ID无效', icon: 'none' }); return }
       self.submitting = true
       try {

+ 2 - 2
cfc-frontend/pages/promotion/index.vue

@@ -274,7 +274,7 @@ export default {
   onShareAppMessage() {
     var path = '/pages/invite/join'
     if (this.shareReferralCode) {
-      path = path + '?inviteCode=' + this.shareReferralCode
+      path = path + '?refCode=' + this.shareReferralCode
     }
     return {
       title: '我在浠艾福发现了好用的家庭成长工具,快来加入!',
@@ -285,7 +285,7 @@ export default {
   onShareTimeline() {
     var query = ''
     if (this.shareReferralCode) {
-      query = 'inviteCode=' + this.shareReferralCode
+      query = 'refCode=' + this.shareReferralCode
     }
     return {
       title: '我在浠艾福发现了好用的家庭成长工具,快来加入!',

+ 1 - 1
cfc-web/.last_build_commit

@@ -1 +1 @@
-c26c7c9f66a91c28b3c97977d842c75cc4e4f157
+51fc0544cd6d8647c8928d85c5f483ed4fafff83

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

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

+ 1 - 1
cfc-web/package.json

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

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

@@ -4,6 +4,27 @@
 
 ---
 
+## v1.0.1329 (2026-09-08)
+
+### Bug 修复
+- AiGateway 超时分离 - connect 快速失败 + read 覆盖 LLM 推理耗时
+- 会员升级自动发JOIN券/用户列表倒序/商品券支付可选/兑换提醒移至支付
+
+### 其他
+- - application.yml: 新增 python.read-timeout-ms: 120000
+- - 前端 api.js: request 支持 timeout 选项(不混入 query),问卷接口加 130s 超时
+- 
+-   grantFamilyJoinCoupons 发放 JOIN 赠券(幂等防重), 记录发券结果
+- - AdminController /users: 无 sort 参数时默认 orderByDesc(createdAt) 倒序
+- - CouponService.toCouponVO: 补 productId 字段, 前端可按商品匹配券
+- - checkout.vue: ownedCoupons/availableCoupons 对 PRODUCT 券按当前商品
+-   productId 匹配(原来一刀切过滤非 ALL 券导致商品券选不到); 新增
+-   affordableExchangeCoupons - CF 不足时不再显示兑换提醒
+- - product-detail.vue: 移除商品页积分兑换优惠券区块, 兑换提醒移至支付时
+-   (无对应券+CF 足够才提示)
+- 
+
+
 ## v1.0.1328 (2026-09-07)
 
 ### Bug 修复

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

@@ -1,6 +1,6 @@
 # 更新日志
 
-> 当前版本: v1.0.1328
+> 当前版本: v1.0.1329
 
 ## 历史版本
 
@@ -8,6 +8,27 @@
 
 ---
 
+## v1.0.1329 (2026-09-08)
+
+### Bug 修复
+- AiGateway 超时分离 - connect 快速失败 + read 覆盖 LLM 推理耗时
+- 会员升级自动发JOIN券/用户列表倒序/商品券支付可选/兑换提醒移至支付
+
+### 其他
+- - application.yml: 新增 python.read-timeout-ms: 120000
+- - 前端 api.js: request 支持 timeout 选项(不混入 query),问卷接口加 130s 超时
+- 
+-   grantFamilyJoinCoupons 发放 JOIN 赠券(幂等防重), 记录发券结果
+- - AdminController /users: 无 sort 参数时默认 orderByDesc(createdAt) 倒序
+- - CouponService.toCouponVO: 补 productId 字段, 前端可按商品匹配券
+- - checkout.vue: ownedCoupons/availableCoupons 对 PRODUCT 券按当前商品
+-   productId 匹配(原来一刀切过滤非 ALL 券导致商品券选不到); 新增
+-   affordableExchangeCoupons - CF 不足时不再显示兑换提醒
+- - product-detail.vue: 移除商品页积分兑换优惠券区块, 兑换提醒移至支付时
+-   (无对应券+CF 足够才提示)
+- 
+
+
 ## v1.0.1328 (2026-09-07)
 
 ### Bug 修复