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

feat(membership): 价格显示到角、家庭成员上限命名、虚拟支付降级普通支付

Sisyphus 1 день назад
Родитель
Сommit
984fec4042

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

@@ -1046,6 +1046,7 @@ public class DatabaseInitializer implements CommandLineRunner {
             insertSysConfigSeed("trial_enabled", "true", "是否启用会员试用");
             insertSysConfigSeed("trial_enabled", "true", "是否启用会员试用");
             insertSysConfigSeed("trial_days", "7", "试用天数");
             insertSysConfigSeed("trial_days", "7", "试用天数");
             insertSysConfigSeed("trial_features", "[\"free_activities\",\"free_courses\",\"teacher_consultation\"]", "试用期间可用功能");
             insertSysConfigSeed("trial_features", "[\"free_activities\",\"free_courses\",\"teacher_consultation\"]", "试用期间可用功能");
+            insertSysConfigSeed("member_pay_virtual_enabled", "1", "会员支付是否使用虚拟支付通道(1=虚拟,0=普通微信)");
             insertSysConfigSeed("health_dimension_weights", "{\"growth\":0.20,\"sleep\":0.15,\"vision\":0.10,\"immunity\":0.15,\"nutrition\":0.15,\"gut\":0.10,\"exercise\":0.15}", "7维健康→身能量权重配置");
             insertSysConfigSeed("health_dimension_weights", "{\"growth\":0.20,\"sleep\":0.15,\"vision\":0.10,\"immunity\":0.15,\"nutrition\":0.15,\"gut\":0.10,\"exercise\":0.15}", "7维健康→身能量权重配置");
             insertSysConfigSeed("health_dimension_sync_factor", "0.5", "7维健康同步至身能量系数");
             insertSysConfigSeed("health_dimension_sync_factor", "0.5", "7维健康同步至身能量系数");
             log.info("SysConfig 种子数据已加载");
             log.info("SysConfig 种子数据已加载");

+ 15 - 14
cfc-backend/src/main/java/com/etotem/cfc/service/MembershipService.java

@@ -524,9 +524,9 @@ public class MembershipService implements MembershipServiceInterface {
      * 创建会员订单并按 member_pay_virtual_enabled 开关决定支付方式。
      * 创建会员订单并按 member_pay_virtual_enabled 开关决定支付方式。
      *
      *
      * @param sessionKey 当前用户 sessionKey(虚拟支付签名用;普通支付时忽略)
      * @param sessionKey 当前用户 sessionKey(虚拟支付签名用;普通支付时忽略)
-     * @param openid     普通支付时需要(JSAPI payer.openid);虚拟支付时可为 null
-     * @return 统一响应 map,含 payType("virtual"/"wechat"/"none")及对应字段;
-     *         虚拟支付道具未配置时返回 null(调用方转 46001)
+      * @param openid     普通支付时需要(JSAPI payer.openid);虚拟支付时可为 null
+      * @return 统一响应 map,含 payType("virtual"/"wechat"/"none")及对应字段;
+      *         虚拟道具未配置时降级为普通支付
      */
      */
     @Transactional(rollbackFor = Exception.class)
     @Transactional(rollbackFor = Exception.class)
     public Map<String, Object> createOrderWithPayType(Long userId, Long familyId, String levelCode,
     public Map<String, Object> createOrderWithPayType(Long userId, Long familyId, String levelCode,
@@ -677,18 +677,19 @@ public class MembershipService implements MembershipServiceInterface {
 
 
         if (virtualEnabled) {
         if (virtualEnabled) {
             VirtualPayParamsDTO dto = virtualPayService.generateMembershipPayParams(mainOrder.getOrderNo(), sessionKey);
             VirtualPayParamsDTO dto = virtualPayService.generateMembershipPayParams(mainOrder.getOrderNo(), sessionKey);
-            if (dto == null) {
-                return null; // 道具未配置,调用方转 46001
+            if (dto != null) {
+                resp.put("payType", "virtual");
+                resp.put("orderInfo", dto.getOrderInfo());
+                resp.put("extInfo", dto.getExtInfo());
+                resp.put("sign", dto.getSign());
+                resp.put("signature", dto.getSignature());
+                resp.put("env", dto.getEnv());
+                resp.put("signType", dto.getSignType());
+                resp.put("currentPeriod", dto.getCurrentPeriod());
+                return resp;
             }
             }
-            resp.put("payType", "virtual");
-            resp.put("orderInfo", dto.getOrderInfo());
-            resp.put("extInfo", dto.getExtInfo());
-            resp.put("sign", dto.getSign());
-            resp.put("signature", dto.getSignature());
-            resp.put("env", dto.getEnv());
-            resp.put("signType", dto.getSignType());
-            resp.put("currentPeriod", dto.getCurrentPeriod());
-            return resp;
+            // 虚拟道具未配置或停用,降级为普通微信支付
+            log.warn("会员虚拟道具未配置或停用,降级普通支付: levelCode={}", levelCode);
         }
         }
 
 
         // 普通微信支付(v3 JSAPI)
         // 普通微信支付(v3 JSAPI)

+ 3 - 3
cfc-frontend/pages/membership/upgrade.vue

@@ -257,9 +257,9 @@ export default {
         }
         }
       }
       }
       if (!plan) return '0'
       if (!plan) return '0'
-      if (periodKey === 'monthly') return plan.monthly ? (plan.monthly / 100).toFixed(0) : '0'
-      if (periodKey === 'quarterly') return plan.quarterly ? (plan.quarterly / 100).toFixed(0) : '0'
-      if (periodKey === 'yearly') return plan.yearly ? (plan.yearly / 100).toFixed(0) : '0'
+      if (periodKey === 'monthly') return plan.monthly ? (plan.monthly / 100).toFixed(1) : '0'
+      if (periodKey === 'quarterly') return plan.quarterly ? (plan.quarterly / 100).toFixed(1) : '0'
+      if (periodKey === 'yearly') return plan.yearly ? (plan.yearly / 100).toFixed(1) : '0'
       return '0'
       return '0'
     },
     },
     goNext: function() {
     goNext: function() {

+ 3 - 3
cfc-web/src/views/admin/MembershipCenter.vue

@@ -53,7 +53,7 @@
               <el-table-column label="原价年费" width="90">
               <el-table-column label="原价年费" width="90">
                 <template slot-scope="{ row }">{{ formatPrice(row.originalPriceYearly) }}</template>
                 <template slot-scope="{ row }">{{ formatPrice(row.originalPriceYearly) }}</template>
               </el-table-column>
               </el-table-column>
-              <el-table-column label="孩子上限" width="90" align="center">
+              <el-table-column label="家庭成员上限" width="100" align="center">
                 <template slot-scope="{ row }">{{ row.maxChildren || '—' }}</template>
                 <template slot-scope="{ row }">{{ row.maxChildren || '—' }}</template>
               </el-table-column>
               </el-table-column>
               <el-table-column label="每日任务" width="90" align="center">
               <el-table-column label="每日任务" width="90" align="center">
@@ -190,7 +190,7 @@
         <el-descriptions :column="2" border size="small">
         <el-descriptions :column="2" border size="small">
           <el-descriptions-item label="月费">{{ formatPrice(currentLevel.priceMonthly) }} 元</el-descriptions-item>
           <el-descriptions-item label="月费">{{ formatPrice(currentLevel.priceMonthly) }} 元</el-descriptions-item>
           <el-descriptions-item label="年费">{{ formatPrice(currentLevel.priceYearly) }} 元</el-descriptions-item>
           <el-descriptions-item label="年费">{{ formatPrice(currentLevel.priceYearly) }} 元</el-descriptions-item>
-          <el-descriptions-item label="孩子上限">{{ currentLevel.maxChildren || '—' }}</el-descriptions-item>
+           <el-descriptions-item label="家庭成员上限">{{ currentLevel.maxChildren || '—' }}</el-descriptions-item>
           <el-descriptions-item label="每日任务上限">{{ currentLevel.maxTasksPerDay || '—' }}</el-descriptions-item>
           <el-descriptions-item label="每日任务上限">{{ currentLevel.maxTasksPerDay || '—' }}</el-descriptions-item>
           <el-descriptions-item label="AI审核">
           <el-descriptions-item label="AI审核">
             <el-tag :type="currentLevel.aiReviewEnabled ? 'success' : 'info'" size="mini">{{ currentLevel.aiReviewEnabled ? '启用' : '未启用' }}</el-tag>
             <el-tag :type="currentLevel.aiReviewEnabled ? 'success' : 'info'" size="mini">{{ currentLevel.aiReviewEnabled ? '启用' : '未启用' }}</el-tag>
@@ -274,7 +274,7 @@
         <el-form-item label="年原价(元)">
         <el-form-item label="年原价(元)">
           <el-input-number v-model="editForm.originalPriceYearly" :min="0" :step="100" :precision="0" style="width:160px;" />
           <el-input-number v-model="editForm.originalPriceYearly" :min="0" :step="100" :precision="0" style="width:160px;" />
         </el-form-item>
         </el-form-item>
-        <el-form-item label="孩子上限">
+        <el-form-item label="家庭成员上限">
           <el-input-number v-model="editForm.maxChildren" :min="0" :max="99" :step="1" style="width:160px;" />
           <el-input-number v-model="editForm.maxChildren" :min="0" :max="99" :step="1" style="width:160px;" />
         </el-form-item>
         </el-form-item>
         <el-form-item label="每日任务上限">
         <el-form-item label="每日任务上限">