Просмотр исходного кода

feat(membership): 福宝/浠宝AI助手会员专属 + 7X24成长教练权益

后端:
- 迁移229: membership_benefits新增GROWTH_COACH权益(FAMILY/PREMIUM)
- MembershipService.canUseFeature: FAMILY/PREMIUM新增mascot_ai功能开关
- schema.sql同步新增GROWTH_COACH种子行

前端:
- ai/chat.vue: onLoad新增getMyMembership检查,FREE用户重定向会员升级页
- user-edit/user-edit.vue: 解锁mascot选择区(FAMILY/PREMIUM可见),FREE用户显示升级提示
- article-detail.vue: startQuiz前检查会员状态,FREE用户跳转升级
- membership/benefits.vue: 新增7X24小时成长教练权益条目
iwt 2 месяцев назад
Родитель
Сommit
b454d17795

+ 10 - 0
cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java

@@ -8845,5 +8845,15 @@ private void runMigration100() {
 		ensureColumn("file_record", "file_type", "VARCHAR(50) DEFAULT NULL COMMENT '文件类型(image/video/doc/etc)'");
 		ensureColumn("file_record", "description", "TEXT COMMENT '文件描述'");
 		log.info("已添加file_record.file_type和description列");
+
+		// 迁移229: 新增GROWTH_COACH权益(7X24小时成长教练)到FAMILY/PREMIUM,及mascot_ai功能开关
+		try {
+			jdbcTemplate.execute("INSERT IGNORE INTO membership_benefits (level_code, benefit_code, benefit_name, benefit_desc, icon, bg_color, sort_order) VALUES " +
+				"('FAMILY', 'GROWTH_COACH', '7X24小时成长教练', 'AI智能教练随时解答家庭教育问题', '🎯', '#FEF3C7', 10), " +
+				"('PREMIUM', 'GROWTH_COACH', '7X24小时成长教练', 'AI智能教练随时解答家庭教育问题 + 优先响应', '🎯', '#FEF3C7', 10)");
+			log.info("已插入GROWTH_COACH权益种子数据");
+		} catch (Exception ex) {
+			log.warn("插入GROWTH_COACH权益种子数据失败: {}", ex.getMessage());
+		}
 	}
 }

+ 4 - 2
cfc-backend/src/main/java/com/etotem/cfc/service/MembershipService.java

@@ -192,7 +192,8 @@ public class MembershipService implements MembershipServiceInterface {
                     || "member_activities".equals(feature)
                     || "create_family".equals(feature)
                     || "invite_family".equals(feature)
-                    || "purchase_commission".equals(feature);
+                    || "purchase_commission".equals(feature)
+                    || "mascot_ai".equals(feature);
         }
 
         // PREMIUM用户可用功能(同FAMILY全部权益)
@@ -205,7 +206,8 @@ public class MembershipService implements MembershipServiceInterface {
                     || "member_activities".equals(feature)
                     || "create_family".equals(feature)
                     || "invite_family".equals(feature)
-                    || "purchase_commission".equals(feature);
+                    || "purchase_commission".equals(feature)
+                    || "mascot_ai".equals(feature);
         }
 
         // PROVIDER也有全部功能

+ 3 - 1
cfc-backend/src/main/resources/schema.sql

@@ -3729,7 +3729,9 @@ INSERT IGNORE INTO membership_benefits (level_code, benefit_code, benefit_name,
 ('PREMIUM', 'PRODUCT_DISCOUNT', '商品会员折扣', '全场商品 6-8 折优惠', '🛒', '#E0E7FF', 6),
 ('PREMIUM', 'COUPON_ACCESS', '优惠券使用权限', '可使用平台优惠券 + 会员专属券', '🎫', '#FEE2E2', 7),
 ('PREMIUM', 'PRIORITY_SUPPORT', '优先客服', '专属客服通道,快速响应', '🎧', '#EDE9FE', 8),
-('PREMIUM', 'TEACHER_CONSULT', '规划师一对一咨询', '每月 1 次成长规划师专业咨询', '👩‍🏫', '#FBCFE8', 9);
+('PREMIUM', 'TEACHER_CONSULT', '规划师一对一咨询', '每月 1 次成长规划师专业咨询', '👩‍🏫', '#FBCFE8', 9),
+('PREMIUM', 'GROWTH_COACH', '7X24小时成长教练', 'AI智能教练随时解答家庭教育问题 + 优先响应', '🎯', '#FEF3C7', 10),
+('FAMILY', 'GROWTH_COACH', '7X24小时成长教练', 'AI智能教练随时解答家庭教育问题', '🎯', '#FEF3C7', 10);
 
 -- ============================================================
 -- 家庭会员订阅表(迁移120)

+ 37 - 23
cfc-frontend/pages/ai/chat.vue

@@ -153,7 +153,7 @@
 </template>
 
 <script>
-import { aiSendMessage, aiGetConversations, aiGetMessages, aiDeleteConversation, aiSendNutritionMessage, aiSendHealthCoachMessage, aiSendHealthButlerMessage } from '../../utils/api.js'
+import { aiSendMessage, aiGetConversations, aiGetMessages, aiDeleteConversation, aiSendNutritionMessage, aiSendHealthCoachMessage, aiSendHealthButlerMessage, getMyMembership } from '../../utils/api.js'
 import BaseEmpty from '../../components/BaseEmpty.vue'
 import AITaskCard from '../../components/AITaskCard.vue'
 import config from '@/config.js'
@@ -226,29 +226,43 @@ export default {
     if (options.firstMessage) {
       this.pendingFirstMessage = decodeURIComponent(options.firstMessage)
     }
-    // 加载用户mascot设置
-    var userInfo = uni.getStorageSync('userInfo')
-    if (userInfo) {
-      if (userInfo.mascot === 'xibao') {
-        this.mascotCode = 'xibao'
-        this.mascotName = '浠宝'
-        this.mascotIcon = '🌟'
-      } else if (userInfo.mascot === 'fubao') {
-        this.mascotCode = 'fubao'
-        this.mascotName = '福宝'
-        this.mascotIcon = '💪'
-      }
-    }
-    this.loadConversations()
-    // 如果有预填消息,自动发送
+    // 会员检查:免费用户不可见福宝/浠宝AI功能
     var self = this
-    if (this.pendingFirstMessage) {
-      this.$nextTick(function() {
-        self.inputText = self.pendingFirstMessage
-        self.pendingFirstMessage = ''
-        self.sendMessage()
-      })
-    }
+    getMyMembership().then(function(res) {
+      if (res.data && res.data.memberLevel && res.data.memberLevel !== 'FREE') {
+        // 加载用户mascot设置
+        var userInfo = uni.getStorageSync('userInfo')
+        if (userInfo) {
+          if (userInfo.mascot === 'xibao') {
+            self.mascotCode = 'xibao'
+            self.mascotName = '浠宝'
+            self.mascotIcon = '🌟'
+          } else if (userInfo.mascot === 'fubao') {
+            self.mascotCode = 'fubao'
+            self.mascotName = '福宝'
+            self.mascotIcon = '💪'
+          }
+        }
+        self.loadConversations()
+        if (self.pendingFirstMessage) {
+          self.$nextTick(function() {
+            self.inputText = self.pendingFirstMessage
+            self.pendingFirstMessage = ''
+            self.sendMessage()
+          })
+        }
+      } else {
+        uni.showToast({ title: '福宝/浠宝是会员专属功能', icon: 'none' })
+        setTimeout(function() {
+          uni.navigateTo({ url: '/pages/membership/upgrade' })
+        }, 1500)
+      }
+    }).catch(function() {
+      uni.showToast({ title: '请先开通会员', icon: 'none' })
+      setTimeout(function() {
+        uni.navigateTo({ url: '/pages/membership/upgrade' })
+      }, 1500)
+    })
   },
   onShow() {
     if (this.pageLoaded) {

+ 7 - 1
cfc-frontend/pages/article-center/article-detail.vue

@@ -79,7 +79,7 @@
 </template>
 
 <script>
-import { getArticleDetail, reportReadingTime, getShareQrCode, completeArticleRead, generateQuiz, submitQuiz } from '@/utils/api.js'
+import { getArticleDetail, reportReadingTime, getShareQrCode, completeArticleRead, generateQuiz, submitQuiz, getMyMembership } from '@/utils/api.js'
 import shareMixin from '../../components/share-mixin.js'
 import ContentSharePoster from '@/components/ContentSharePoster.vue'
 import config from '@/config.js'
@@ -222,6 +222,12 @@ export default {
     // 答题
     async startQuiz() {
       try {
+        var memRes = await getMyMembership()
+        if (memRes.data && memRes.data.memberLevel && memRes.data.memberLevel === 'FREE') {
+          uni.showToast({ title: '浠宝/福宝答题是会员专属', icon: 'none' })
+          setTimeout(function() { uni.navigateTo({ url: '/pages/membership/upgrade' }) }, 1500)
+          return
+        }
         var res = await generateQuiz({ articleId: this.articleId })
         if (res.code === 200 && res.data && res.data.length > 0) {
           this.quizQuestions = res.data

+ 15 - 4
cfc-frontend/pages/membership/benefits.vue

@@ -163,17 +163,28 @@ export default {
           usedAt: null,
           detail: '通俗易懂的解读 + 行动建议'
         },
-        { 
-          code: 'MANAGER_SERVICE', 
-          name: '专属健康教练服务', 
+        {
+          code: 'MANAGER_SERVICE',
+          name: '专属健康教练服务',
           desc: '认证健康教练月度随访',
-          icon: '👨‍🏫', 
+          icon: '👨‍🏫',
           bg: '#FFEDD5',
           canUse: true,
           used: false,
           usedAt: null,
           detail: '15-20 分钟电话随访 + 在线答疑'
         },
+        {
+          code: 'GROWTH_COACH',
+          name: '7X24小时成长教练',
+          desc: 'AI智能教练随时解答家庭教育问题',
+          icon: '🎯',
+          bg: '#FEF3C7',
+          canUse: true,
+          used: false,
+          usedAt: null,
+          detail: '浠宝/福宝AI助手,随时回答育儿、学习、情绪等问题'
+        },
         { 
           code: 'PRODUCT_DISCOUNT', 
           name: '商品会员折扣', 

+ 48 - 4
cfc-frontend/pages/user-edit/user-edit.vue

@@ -203,8 +203,8 @@
 			</view>
 		</view>
 
-		<!-- AI助手选择(已屏蔽)
-		<view class="family-section" v-if="isEdit">
+		<!-- AI助手选择(会员专属) -->
+		<view class="family-section" v-if="isEdit && memberLevel !== 'FREE'">
 			<view class="section-title">🤖 选择AI助手</view>
 			<view class="mascot-cards">
 				<view class="mascot-card" :class="{ active: form.mascot === 'xibao' }" @click="selectMascot('xibao')">
@@ -222,7 +222,15 @@
 					</view>
 				</view>
 			</view>
-		</view> -->
+		</view>
+		<!-- 免费用户提示 -->
+		<view class="family-section" v-if="isEdit && memberLevel === 'FREE'">
+			<view class="mascot-locked-hint" @click="goUpgrade">
+				<text class="locked-icon">🔒</text>
+				<text class="locked-text">开通会员解锁浠宝/福宝AI助手</text>
+				<text class="locked-arrow">›</text>
+			</view>
+		</view>
 
 		<!-- 新用户流程:保存资料 / 跳过(不再创建或加入家庭) -->
 		<view class="family-section" v-if="isEdit && form.role !== 'teacher' && isNewUserFlow">
@@ -295,7 +303,7 @@
 </template>
 
 <script>
-import { updateUserInfo, createFamily, directRegister, getUserInfo, requestJoinByCode } from '../../utils/api.js'
+import { updateUserInfo, createFamily, directRegister, getUserInfo, requestJoinByCode, getMyMembership } from '../../utils/api.js'
 import config from '@/config.js'
 
 export default {
@@ -304,6 +312,7 @@ export default {
 			isEdit: false,
 			showRoleSelect: true,
 			isNewUserFlow: false,  // 是否是新用户注册流程
+			memberLevel: 'FREE', // 会员等级,用于判断是否解锁AI助手
 			form: {
 				role: '',
 				avatar: '',
@@ -424,6 +433,13 @@ export default {
 		if (this.isEdit && !this.isNewUserFlow) {
 			this.loadUserInfo()
 		}
+		// 加载会员等级(用于AI助手解锁)
+		var self = this
+		getMyMembership().then(function(res) {
+			if (res.data && res.data.memberLevel) {
+				self.memberLevel = res.data.memberLevel
+			}
+		}).catch(function() {})
 	},
 	methods: {
 		selectRole(role) {
@@ -500,6 +516,9 @@ export default {
 	selectMascot(code) {
 		this.form.mascot = code
 	},
+	goUpgrade() {
+		uni.navigateTo({ url: '/pages/membership/upgrade' })
+	},
 	// ===== 省市区三级联动弹窗(与订单收货人地址一致) =====
 	openRegionPicker() {
 		this.tempProvince = this.form.province ? { name: this.form.province, id: null } : null
@@ -1269,4 +1288,29 @@ export default {
 	color: #ccc;
 	margin-left: 8rpx;
 }
+
+/* AI助手锁定提示 */
+.mascot-locked-hint {
+	display: flex;
+	align-items: center;
+	padding: 28rpx 32rpx;
+	background: linear-gradient(135deg, #FEF3C7, #FDE68A);
+	border-radius: 20rpx;
+	margin-top: 16rpx;
+}
+.locked-icon {
+	font-size: 36rpx;
+	margin-right: 16rpx;
+}
+.locked-text {
+	flex: 1;
+	font-size: 28rpx;
+	font-weight: 600;
+	color: #92400e;
+}
+.locked-arrow {
+	font-size: 32rpx;
+	color: #92400e;
+	margin-left: 8rpx;
+}
 </style>

+ 1 - 1
cfc-web/.last_build_commit

@@ -1 +1 @@
-61bbcf72ffa12016be1dad22c54e3794ba07621c
+a65d8969ed58b7c531781e52284584b87cefd7cb

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

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