From 8d326b853cd3f2d2ca5f9a70b343389da63d9af6 Mon Sep 17 00:00:00 2001
From: KKSU <15274802129@163.com>
Date: Mon, 23 Dec 2024 18:00:00 +0800
Subject: [PATCH] feat(mall): 新增节点规则功能

---
 src/main/resources/templates/febs/views/modules/runVip/vipEdit.html          |    4 
 src/main/java/cc/mrbird/febs/common/enumerates/RunVipMoneyFlowTypeEnum.java  |    5 
 src/main/java/cc/mrbird/febs/mall/controller/AdminRunVipController.java      |   27 +
 src/main/java/cc/mrbird/febs/mall/entity/RunNodeSet.java                     |   17 +
 src/main/resources/templates/febs/views/modules/runVip/nodeList.html         |  146 +++++++++
 src/main/java/cc/mrbird/febs/mall/service/IMemberProfitService.java          |    2 
 src/main/java/cc/mrbird/febs/mall/controller/ViewRunVipController.java       |   22 +
 src/main/java/cc/mrbird/febs/mall/service/IAdminRunVipService.java           |   13 
 src/main/java/cc/mrbird/febs/mall/entity/MallMember.java                     |    7 
 src/main/java/cc/mrbird/febs/mall/mapper/RunNodeSetMapper.java               |    7 
 src/main/java/cc/mrbird/febs/mall/service/AsyncService.java                  |    3 
 src/main/java/cc/mrbird/febs/mall/service/impl/AdminRunVipServiceImpl.java   |   36 +
 src/main/resources/templates/febs/views/modules/runVip/vipAdd.html           |    4 
 src/main/java/cc/mrbird/febs/common/enumerates/RunVipDataDictionaryEnum.java |    7 
 src/main/java/cc/mrbird/febs/mall/service/impl/AgentServiceImpl.java         |  171 +++++++----
 src/main/java/cc/mrbird/febs/mall/service/impl/MemberProfitServiceImpl.java  |   95 ++++++
 src/main/java/cc/mrbird/febs/mall/quartz/ProfitJob.java                      |   43 +-
 src/main/java/cc/mrbird/febs/mall/service/impl/AsyncServiceImpl.java         |   27 +
 src/main/resources/templates/febs/views/modules/runVip/nodeEdit.html         |  111 +++++++
 src/main/resources/templates/febs/views/modules/runVip/nodeAdd.html          |  105 +++++++
 20 files changed, 751 insertions(+), 101 deletions(-)

diff --git a/src/main/java/cc/mrbird/febs/common/enumerates/RunVipDataDictionaryEnum.java b/src/main/java/cc/mrbird/febs/common/enumerates/RunVipDataDictionaryEnum.java
index 6d44429..a853314 100644
--- a/src/main/java/cc/mrbird/febs/common/enumerates/RunVipDataDictionaryEnum.java
+++ b/src/main/java/cc/mrbird/febs/common/enumerates/RunVipDataDictionaryEnum.java
@@ -5,6 +5,13 @@
 @Getter
 public enum RunVipDataDictionaryEnum {
 
+    //节点升级-直推人数
+    NODE_DIRECT_CNT("CHARGE_TYPE", "NODE_DIRECT_CNT"),
+    //节点升级-团队人数
+    NODE_TEAM_CNT("CHARGE_TYPE", "NODE_TEAM_CNT"),
+    //节点升级-业绩要求
+    NODE_ACHIEVE_CNT("CHARGE_TYPE", "NODE_ACHIEVE_CNT"),
+
     //释放碳积分的开始结束时间
     RUN_START_TIME("CHARGE_TYPE", "RUN_START_TIME"),
     RUN_END_TIME("CHARGE_TYPE", "RUN_END_TIME"),
diff --git a/src/main/java/cc/mrbird/febs/common/enumerates/RunVipMoneyFlowTypeEnum.java b/src/main/java/cc/mrbird/febs/common/enumerates/RunVipMoneyFlowTypeEnum.java
index 845351c..6bf02bf 100644
--- a/src/main/java/cc/mrbird/febs/common/enumerates/RunVipMoneyFlowTypeEnum.java
+++ b/src/main/java/cc/mrbird/febs/common/enumerates/RunVipMoneyFlowTypeEnum.java
@@ -6,6 +6,11 @@
 public enum RunVipMoneyFlowTypeEnum {
 
     /**
+     * 节点助力
+     */
+    NODE_BALANCE(10,"节点助力碳币{}","节点助力"),
+
+    /**
      * 获得碳积分
      */
     GET_SCORE(9,"本次获得碳积分{}","获得碳积分"),
diff --git a/src/main/java/cc/mrbird/febs/mall/controller/AdminRunVipController.java b/src/main/java/cc/mrbird/febs/mall/controller/AdminRunVipController.java
index 52aefd3..2f7fa89 100644
--- a/src/main/java/cc/mrbird/febs/mall/controller/AdminRunVipController.java
+++ b/src/main/java/cc/mrbird/febs/mall/controller/AdminRunVipController.java
@@ -4,10 +4,7 @@
 import cc.mrbird.febs.common.controller.BaseController;
 import cc.mrbird.febs.common.entity.FebsResponse;
 import cc.mrbird.febs.common.entity.QueryRequest;
-import cc.mrbird.febs.mall.entity.MallCharge;
-import cc.mrbird.febs.mall.entity.MallMember;
-import cc.mrbird.febs.mall.entity.MallMemberWithdraw;
-import cc.mrbird.febs.mall.entity.RunVip;
+import cc.mrbird.febs.mall.entity.*;
 import cc.mrbird.febs.mall.mapper.MallMemberMapper;
 import cc.mrbird.febs.mall.service.IAdminRunVipService;
 import cc.mrbird.febs.mall.service.ISystemService;
@@ -82,6 +79,12 @@
         return new FebsResponse().success().data(data);
     }
 
+    @GetMapping("/nodeList")
+    public FebsResponse nodeList(RunNodeSet runNodeSet, QueryRequest request) {
+        Map<String, Object> data = getDataTable(iAdminRunVipService.nodeListInPage(runNodeSet,request));
+        return new FebsResponse().success().data(data);
+    }
+
     @PostMapping(value = "/addOrEdit")
     public FebsResponse addOrEdit(@RequestBody RunVip config) {
         if (config.getId() == null) {
@@ -92,6 +95,22 @@
         return new FebsResponse().success().message("操作成功");
     }
 
+    @PostMapping(value = "/nodeAddOrEdit")
+    public FebsResponse nodeAddOrEdit(@RequestBody RunNodeSet config) {
+        if (config.getId() == null) {
+            iAdminRunVipService.addRunNodeSet(config);
+        } else {
+            iAdminRunVipService.editRunNodeSet(config);
+        }
+        return new FebsResponse().success().message("操作成功");
+    }
+
+    @GetMapping(value = "/nodeDel/{id}")
+    public FebsResponse nodeDel(@PathVariable("id") Long id) {
+        iAdminRunVipService.deleteNodeById(id);
+        return new FebsResponse().success().message("操作成功");
+    }
+
     @GetMapping(value = "/del/{id}")
     public FebsResponse del(@PathVariable("id") Long id) {
         iAdminRunVipService.getBaseMapper().deleteById(id);
diff --git a/src/main/java/cc/mrbird/febs/mall/controller/ViewRunVipController.java b/src/main/java/cc/mrbird/febs/mall/controller/ViewRunVipController.java
index 4dc0c67..c2e1134 100644
--- a/src/main/java/cc/mrbird/febs/mall/controller/ViewRunVipController.java
+++ b/src/main/java/cc/mrbird/febs/mall/controller/ViewRunVipController.java
@@ -2,7 +2,9 @@
 
 import cc.mrbird.febs.common.entity.FebsConstant;
 import cc.mrbird.febs.common.utils.FebsUtil;
+import cc.mrbird.febs.mall.entity.RunNodeSet;
 import cc.mrbird.febs.mall.entity.RunVip;
+import cc.mrbird.febs.mall.mapper.RunNodeSetMapper;
 import cc.mrbird.febs.mall.service.IAdminRunVipService;
 import lombok.RequiredArgsConstructor;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -18,6 +20,7 @@
 public class ViewRunVipController{
 
     private final IAdminRunVipService iAdminRunVipService;
+    private final RunNodeSetMapper runNodeSetMapper;
     @GetMapping(value = "/sellVipList")
     @RequiresPermissions("sellVipList:view")
     public String sellVipList() {
@@ -33,12 +36,10 @@
     public String runVipList() {
         return FebsUtil.view("modules/runVip/runVipList");
     }
-
     @GetMapping(value = "/vipAdd")
     public String levelAdd() {
         return FebsUtil.view("modules/runVip/vipAdd");
     }
-
     @GetMapping("/vipEdit/{id}")
     public String vipEdit(@PathVariable("id") Long id, Model model) {
         RunVip runVip = iAdminRunVipService.getBaseMapper().selectById(id);
@@ -52,4 +53,21 @@
         return FebsUtil.view("modules/runVip/systemSetting");
     }
 
+
+    @GetMapping(value = "/nodeList")
+    @RequiresPermissions("nodeList:view")
+    public String nodeList() {
+        return FebsUtil.view("modules/runVip/nodeList");
+    }
+    @GetMapping(value = "/nodeAdd")
+    public String nodeAdd() {
+        return FebsUtil.view("modules/runVip/nodeAdd");
+    }
+    @GetMapping("/nodeEdit/{id}")
+    public String nodeEdit(@PathVariable("id") Long id, Model model) {
+        RunNodeSet runNodeSet = runNodeSetMapper.selectById(id);
+        model.addAttribute("runNodeSet", runNodeSet);
+        return FebsUtil.view("modules/runVip/nodeEdit");
+    }
+
 }
diff --git a/src/main/java/cc/mrbird/febs/mall/entity/MallMember.java b/src/main/java/cc/mrbird/febs/mall/entity/MallMember.java
index 145534b..f564d01 100644
--- a/src/main/java/cc/mrbird/febs/mall/entity/MallMember.java
+++ b/src/main/java/cc/mrbird/febs/mall/entity/MallMember.java
@@ -126,9 +126,13 @@
     private String levelName;
 
     /**
-     * 董事
+     * 是否是节点 1是 0否
      */
     private Integer director;
+    //升级为节点的时间
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date directorTime;
 
     /**
      * 店长
@@ -180,6 +184,7 @@
 
     private Date lastLoginTime;
 
+    //升级为会员的时间
     @DateTimeFormat(pattern = "yyyy-MM-dd")
     @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
     private Date vipLevelTime;
diff --git a/src/main/java/cc/mrbird/febs/mall/entity/RunNodeSet.java b/src/main/java/cc/mrbird/febs/mall/entity/RunNodeSet.java
new file mode 100644
index 0000000..10ebaa6
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/mall/entity/RunNodeSet.java
@@ -0,0 +1,17 @@
+package cc.mrbird.febs.mall.entity;
+
+import cc.mrbird.febs.common.entity.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@TableName("run_node_set")
+public class RunNodeSet extends BaseEntity {
+
+    private Integer orderNumber;
+    private BigDecimal minAchieve;
+    private BigDecimal maxAchieve;
+    private String nodePercent;//奖励碳币比例
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/mapper/RunNodeSetMapper.java b/src/main/java/cc/mrbird/febs/mall/mapper/RunNodeSetMapper.java
new file mode 100644
index 0000000..ec31b93
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/mall/mapper/RunNodeSetMapper.java
@@ -0,0 +1,7 @@
+package cc.mrbird.febs.mall.mapper;
+
+import cc.mrbird.febs.mall.entity.RunNodeSet;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface RunNodeSetMapper extends BaseMapper<RunNodeSet> {
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/quartz/ProfitJob.java b/src/main/java/cc/mrbird/febs/mall/quartz/ProfitJob.java
index 704ddc6..1a795d5 100644
--- a/src/main/java/cc/mrbird/febs/mall/quartz/ProfitJob.java
+++ b/src/main/java/cc/mrbird/febs/mall/quartz/ProfitJob.java
@@ -15,23 +15,23 @@
     @Autowired
     private IMemberProfitService memberProfitService;
 
-    /**
-     * 每12小时更新一次会员等级
-     * 套餐过期后,更新用户为游客等级
-     */
-    @Scheduled(cron = "0 0 0/12 * * ?")
-    public void updateMemberLevel() {
-        memberProfitService.updateMemberLevel();
-    }
-
-    /**
-     * 每天凌晨
-     * 清空用户的碳积分
-     */
-    @Scheduled(cron = "0 0 0 * * ?")
-    public void updateMemberScore() {
-        memberProfitService.updateMemberScore();
-    }
+//    /**
+//     * 每12小时更新一次会员等级
+//     * 套餐过期后,更新用户为游客等级
+//     */
+//    @Scheduled(cron = "0 0 0/12 * * ?")
+//    public void updateMemberLevel() {
+//        memberProfitService.updateMemberLevel();
+//    }
+//
+//    /**
+//     * 每天凌晨
+//     * 清空用户的碳积分
+//     */
+//    @Scheduled(cron = "0 0 0 * * ?")
+//    public void updateMemberScore() {
+//        memberProfitService.updateMemberScore();
+//    }
 
     /**
      * 每1小时执行一次
@@ -42,4 +42,13 @@
     public void updateRunScore() {
         memberProfitService.updateRunScore();
     }
+
+    /**
+     * 每个月一号
+     *      节点奖励分发
+     */
+    @Scheduled(cron = "0 0 1 * *")
+    public void updateNodeScore() {
+        memberProfitService.updateNodeScore();
+    }
 }
diff --git a/src/main/java/cc/mrbird/febs/mall/service/AsyncService.java b/src/main/java/cc/mrbird/febs/mall/service/AsyncService.java
index b217db9..dbedd8a 100644
--- a/src/main/java/cc/mrbird/febs/mall/service/AsyncService.java
+++ b/src/main/java/cc/mrbird/febs/mall/service/AsyncService.java
@@ -11,4 +11,7 @@
 
     @Async(FebsConstant.ASYNC_POOL)
     void releaseScore(BigDecimal amount,Long memberId);
+
+    @Async(FebsConstant.ASYNC_POOL)
+    void releaseNodeCoin(BigDecimal amount,BigDecimal percent,BigDecimal balanceToCoin,Long memberId);
 }
diff --git a/src/main/java/cc/mrbird/febs/mall/service/IAdminRunVipService.java b/src/main/java/cc/mrbird/febs/mall/service/IAdminRunVipService.java
index 7d71dbe..8e09cca 100644
--- a/src/main/java/cc/mrbird/febs/mall/service/IAdminRunVipService.java
+++ b/src/main/java/cc/mrbird/febs/mall/service/IAdminRunVipService.java
@@ -2,10 +2,7 @@
 
 import cc.mrbird.febs.common.entity.FebsResponse;
 import cc.mrbird.febs.common.entity.QueryRequest;
-import cc.mrbird.febs.mall.entity.MallCharge;
-import cc.mrbird.febs.mall.entity.MallMemberWithdraw;
-import cc.mrbird.febs.mall.entity.MallMoneyFlow;
-import cc.mrbird.febs.mall.entity.RunVip;
+import cc.mrbird.febs.mall.entity.*;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 
@@ -14,6 +11,8 @@
 public interface IAdminRunVipService extends IService<RunVip> {
 
     IPage<RunVip> runVipListInPage(RunVip runVip,QueryRequest request);
+
+    IPage<RunNodeSet> nodeListInPage(RunNodeSet runNodeSet, QueryRequest request);
 
     void addVip(RunVip config);
 
@@ -28,4 +27,10 @@
     IPage<MallMemberWithdraw> sellList(MallMemberWithdraw mallMemberWithdraw, QueryRequest request);
 
     List<MallMoneyFlow> allMoneyType();
+
+    void addRunNodeSet(RunNodeSet config);
+
+    void editRunNodeSet(RunNodeSet config);
+
+    void deleteNodeById(Long id);
 }
diff --git a/src/main/java/cc/mrbird/febs/mall/service/IMemberProfitService.java b/src/main/java/cc/mrbird/febs/mall/service/IMemberProfitService.java
index 3c81cef..02600f6 100644
--- a/src/main/java/cc/mrbird/febs/mall/service/IMemberProfitService.java
+++ b/src/main/java/cc/mrbird/febs/mall/service/IMemberProfitService.java
@@ -47,4 +47,6 @@
     void updateRunScore();
 
     void updateMemberScore();
+
+    void updateNodeScore();
 }
diff --git a/src/main/java/cc/mrbird/febs/mall/service/impl/AdminRunVipServiceImpl.java b/src/main/java/cc/mrbird/febs/mall/service/impl/AdminRunVipServiceImpl.java
index 7aa03f5..8cbd603 100644
--- a/src/main/java/cc/mrbird/febs/mall/service/impl/AdminRunVipServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/mall/service/impl/AdminRunVipServiceImpl.java
@@ -5,14 +5,8 @@
 import cc.mrbird.febs.common.enumerates.RunVipMoneyFlowTypeEnum;
 import cc.mrbird.febs.common.enumerates.YesOrNoEnum;
 import cc.mrbird.febs.common.exception.FebsException;
-import cc.mrbird.febs.mall.entity.MallCharge;
-import cc.mrbird.febs.mall.entity.MallMemberWithdraw;
-import cc.mrbird.febs.mall.entity.MallMoneyFlow;
-import cc.mrbird.febs.mall.entity.RunVip;
-import cc.mrbird.febs.mall.mapper.MallChargeMapper;
-import cc.mrbird.febs.mall.mapper.MallMemberWithdrawMapper;
-import cc.mrbird.febs.mall.mapper.MallMoneyFlowMapper;
-import cc.mrbird.febs.mall.mapper.RunVipMapper;
+import cc.mrbird.febs.mall.entity.*;
+import cc.mrbird.febs.mall.mapper.*;
 import cc.mrbird.febs.mall.service.IAdminRunVipService;
 import cc.mrbird.febs.mall.service.IApiMallMemberWalletService;
 import cc.mrbird.febs.rabbit.producter.AgentProducer;
@@ -40,10 +34,21 @@
     private final MallMoneyFlowMapper mallMoneyFlowMapper;
     private final AgentProducer agentProducer;
     private final IApiMallMemberWalletService walletService;
+    private final RunNodeSetMapper runNodeSetMapper;
     @Override
     public IPage<RunVip> runVipListInPage(RunVip runVip,QueryRequest request) {
         Page<RunVip> page = new Page<>(request.getPageNum(), request.getPageSize());
         return this.baseMapper.selectRunVipListInPage(page);
+    }
+
+    @Override
+    public IPage<RunNodeSet> nodeListInPage(RunNodeSet runNodeSet, QueryRequest request) {
+        Page<RunNodeSet> page = new Page<>(request.getPageNum(), request.getPageSize());
+        return runNodeSetMapper.selectPage(
+                page,
+                new LambdaQueryWrapper<RunNodeSet>()
+                        .orderByAsc(RunNodeSet::getOrderNumber)
+        );
     }
 
     @Override
@@ -137,4 +142,19 @@
 
         return mallMoneyFlows;
     }
+
+    @Override
+    public void addRunNodeSet(RunNodeSet config) {
+        runNodeSetMapper.insert(config);
+    }
+
+    @Override
+    public void editRunNodeSet(RunNodeSet config) {
+        runNodeSetMapper.updateById(config);
+    }
+
+    @Override
+    public void deleteNodeById(Long id) {
+        runNodeSetMapper.deleteById(id);
+    }
 }
diff --git a/src/main/java/cc/mrbird/febs/mall/service/impl/AgentServiceImpl.java b/src/main/java/cc/mrbird/febs/mall/service/impl/AgentServiceImpl.java
index ee71133..9091b6b 100644
--- a/src/main/java/cc/mrbird/febs/mall/service/impl/AgentServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/mall/service/impl/AgentServiceImpl.java
@@ -1,9 +1,13 @@
 package cc.mrbird.febs.mall.service.impl;
 
-import cc.mrbird.febs.common.enumerates.*;
-import cc.mrbird.febs.common.utils.MallUtils;
+import cc.mrbird.febs.common.enumerates.AgentLevelEnum;
+import cc.mrbird.febs.common.enumerates.RunVipDataDictionaryEnum;
+import cc.mrbird.febs.common.enumerates.YesOrNoEnum;
 import cc.mrbird.febs.mall.dto.ApiMemberChargeFailDto;
-import cc.mrbird.febs.mall.entity.*;
+import cc.mrbird.febs.mall.entity.AgentInfo;
+import cc.mrbird.febs.mall.entity.DataDictionaryCustom;
+import cc.mrbird.febs.mall.entity.MallCharge;
+import cc.mrbird.febs.mall.entity.MallMember;
 import cc.mrbird.febs.mall.mapper.DataDictionaryCustomMapper;
 import cc.mrbird.febs.mall.mapper.MallChargeMapper;
 import cc.mrbird.febs.mall.mapper.MallMemberMapper;
@@ -12,7 +16,6 @@
 import cc.mrbird.febs.mall.service.IApiMallMemberService;
 import cc.mrbird.febs.mall.service.IApiMallMemberWalletService;
 import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
@@ -24,8 +27,9 @@
 import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
-import java.math.RoundingMode;
 import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * @author wzy
@@ -192,73 +196,118 @@
         mallChargeMapper.updateById(mallCharge);
     }
 
+    /**
+     * 购买会员看你的上级和上上级是否满足升级节点的条件
+     *      直推 10人
+     *      团队 50人
+     *      团队总业绩 10000
+     *   满足以上三个条件
+     *      更新升级节点的时间
+     */
+    private void NodeUp(Long memberId,Integer directCnt,Integer teamCnt,BigDecimal achieveCnt){
+        try {
+            // 获取会员信息
+            MallMember mallMember = mallMemberMapper.selectById(memberId);
+            if (mallMember == null) {
+                throw new IllegalArgumentException("会员不存在");
+            }
+
+            // 已经是节点则跳过
+            if (YesOrNoEnum.YES.getValue() == mallMember.getDirector()) {
+                return;
+            }
+
+            // 获取直推成员和团队成员
+            List<MallMember> allMembers = mallMemberMapper.selectList(
+                    new LambdaQueryWrapper<MallMember>()
+                            .eq(MallMember::getReferrerId, mallMember.getInviteId())
+                            .or()
+                            .in(MallMember::getReferrerId, mallMemberMapper.selectList(
+                                    new LambdaQueryWrapper<MallMember>()
+                                            .eq(MallMember::getReferrerId, mallMember.getInviteId())
+                            ).stream()
+                                    .map(MallMember::getInviteId)
+                                    .collect(Collectors.toSet()))
+            );
+
+            if (allMembers == null || allMembers.isEmpty()) {
+                return;
+            }
+
+            // 检查直推人数
+            long directCount = allMembers.stream()
+                    .filter(member -> mallMember.getInviteId().equals(member.getReferrerId()))
+                    .count();
+            if (directCount < directCnt) {
+                return;
+            }
+
+            // 检查团队人数
+            if (allMembers.size() < teamCnt) {
+                return;
+            }
+
+            // 获取团队业绩(不包含本人业绩)
+            Set<Long> memberIds = allMembers.stream()
+                    .map(MallMember::getId)
+                    .collect(Collectors.toSet());
+
+            List<MallCharge> mallCharges = mallChargeMapper.selectList(
+                    new LambdaQueryWrapper<MallCharge>()
+                            .in(MallCharge::getMemberId, memberIds)
+                            .eq(MallCharge::getState, YesOrNoEnum.YES.getValue())
+            );
+
+            BigDecimal totalCharge = mallCharges.stream()
+                    .map(MallCharge::getAmount)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+            if (totalCharge.compareTo(achieveCnt) < 0) {
+                return;
+            }
+
+            mallMember.setDirector(YesOrNoEnum.YES.getValue());
+            mallMember.setDirectorTime(DateUtil.date());
+            mallMemberMapper.updateById(mallMember);
+        } catch (Exception e) {
+            // 记录日志并处理异常
+            log.error("会员升级节点失败: {}", memberId, e);
+            throw new RuntimeException("会员升级节点失败", e);
+        }
+    }
     @Override
     public void buyVipSuccessMsg(Long chargeId) {
         MallCharge mallCharge = mallChargeMapper.selectById(chargeId);
-        //更新会员的等级和过期时间
+        //更新会员的等级和会员升级的时间
         Long memberId = mallCharge.getMemberId();
         String vipCode = mallCharge.getVipCode();
-        DateTime dateTime = DateUtil.offsetMonth(DateUtil.date(), 1);
-        mallMemberMapper.updateVipLevelTimeAndLevel(memberId,dateTime,vipCode);
+        mallMemberMapper.updateVipLevelTimeAndLevel(memberId,DateUtil.date(),vipCode);
+        DataDictionaryCustom directCntDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(
+                RunVipDataDictionaryEnum.NODE_DIRECT_CNT.getType(),
+                RunVipDataDictionaryEnum.NODE_DIRECT_CNT.getCode());
+        Integer directCnt = Integer.parseInt(directCntDic.getValue());
+        DataDictionaryCustom teamCntDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(
+                RunVipDataDictionaryEnum.NODE_TEAM_CNT.getType(),
+                RunVipDataDictionaryEnum.NODE_TEAM_CNT.getCode());
+        Integer teamCnt = Integer.parseInt(teamCntDic.getValue());
+        DataDictionaryCustom achieveCntDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(
+                RunVipDataDictionaryEnum.NODE_ACHIEVE_CNT.getType(),
+                RunVipDataDictionaryEnum.NODE_ACHIEVE_CNT.getCode());
+        BigDecimal achieveCnt = new BigDecimal(achieveCntDic.getValue());
 
-        //购买成功后,是否返利上级
         MallMember mallMember = mallMemberMapper.selectById(memberId);
-        if(null == mallMember.getReferrerId()){
+        if(StrUtil.isEmpty(mallMember.getReferrerId())){
             return;
         }
+        //上级
+        MallMember parentMember = mallMemberMapper.selectInfoByInviteId(mallMember.getReferrerId());
+        NodeUp(parentMember.getId(),directCnt,teamCnt,achieveCnt);
 
-        RunVip runVip = runVipMapper.selectOne(new LambdaQueryWrapper<RunVip>().eq(RunVip::getVipCode, vipCode));
-        BigDecimal rebatePercent = runVip.getRebatePercent();
-        BigDecimal amount = mallCharge.getAmount();
-        BigDecimal rebateAmount = amount.multiply(rebatePercent).setScale(2, RoundingMode.DOWN);
-        BigDecimal balanceToCoin =
-                new BigDecimal(
-                        dataDictionaryCustomMapper.selectDicDataByTypeAndCode(
-                                RunVipDataDictionaryEnum.RUN_VIP_BALANCE_TO_COIN.getType(),
-                                RunVipDataDictionaryEnum.RUN_VIP_BALANCE_TO_COIN.getCode()
-                        ).getValue()
-                );
-        BigDecimal rebateCoin = rebateAmount.divide(balanceToCoin, 2, RoundingMode.DOWN);
-        if(BigDecimal.ZERO.compareTo(rebateCoin) >= 0){
+        if(StrUtil.isEmpty(parentMember.getReferrerId())){
             return;
         }
-        MallMember parent = mallMemberMapper.selectInfoByInviteId(mallMember.getReferrerId());
-        if(null == parent){
-            return;
-        }
-        String orderNo = MallUtils.getOrderNum("FL");
-        if(null != parent.getReferrerId()){
-            BigDecimal rebateCoinGrandpa = rebateCoin.multiply(rebatePercent).setScale(2, RoundingMode.DOWN);
-            MallMember grandpa = mallMemberMapper.selectInfoByInviteId(parent.getReferrerId());
-            if(null != grandpa){
-                if(BigDecimal.ZERO.compareTo(rebateCoinGrandpa) < 0){
-                    //返利给上上级
-                    walletService.addBalance(rebateCoinGrandpa,grandpa.getId());
-                    mallMemberService.runVipMoneyFlowAdd(
-                            grandpa.getId(),
-                            mallMember.getId(),
-                            orderNo,
-                            FlowTypeEnum.BALANCE.getValue(),
-                            RunVipMoneyFlowTypeEnum.BUY_VIP_REBATE.getValue(),
-                            rebateCoinGrandpa,
-                            StrUtil.format(RunVipMoneyFlowTypeEnum.BUY_VIP_REBATE.getDescription(),mallMember.getPhone(),runVip.getVipName(),rebateCoinGrandpa),
-                            YesOrNoEnum.YES.getValue()
-                    );
-                    rebateCoin = rebateCoin.subtract(rebateCoinGrandpa).setScale(2, RoundingMode.DOWN);
-                }
-            }
-        }
-        //返利给上级
-        walletService.addBalance(rebateCoin,parent.getId());
-        mallMemberService.runVipMoneyFlowAdd(
-                parent.getId(),
-                mallMember.getId(),
-                orderNo,
-                FlowTypeEnum.BALANCE.getValue(),
-                RunVipMoneyFlowTypeEnum.BUY_VIP_REBATE.getValue(),
-                rebateCoin,
-                StrUtil.format(RunVipMoneyFlowTypeEnum.BUY_VIP_REBATE.getDescription(),mallMember.getPhone(),runVip.getVipName(),rebateCoin),
-                YesOrNoEnum.YES.getValue()
-        );
+        //上上级
+        MallMember graMember = mallMemberMapper.selectInfoByInviteId(parentMember.getReferrerId());
+        NodeUp(graMember.getId(),directCnt,teamCnt,achieveCnt);
     }
 }
diff --git a/src/main/java/cc/mrbird/febs/mall/service/impl/AsyncServiceImpl.java b/src/main/java/cc/mrbird/febs/mall/service/impl/AsyncServiceImpl.java
index bef028b..d661692 100644
--- a/src/main/java/cc/mrbird/febs/mall/service/impl/AsyncServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/mall/service/impl/AsyncServiceImpl.java
@@ -16,6 +16,7 @@
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 
 @Slf4j
 @Service
@@ -40,4 +41,30 @@
         );
 
     }
+
+    @Override
+    public void releaseNodeCoin(BigDecimal amount, BigDecimal percent, BigDecimal balanceToCoin,Long memberId) {
+        //实际节点返利的金额
+        BigDecimal multiply = amount.multiply(percent);
+        if(BigDecimal.ZERO.compareTo(multiply) >=0){
+            return;
+        }
+        BigDecimal divide = multiply.divide(balanceToCoin, 2, RoundingMode.DOWN);
+        if(BigDecimal.ZERO.compareTo(divide) >=0){
+            return;
+        }
+        walletService.addBalance(divide,memberId);
+        String orderNo = MallUtils.getOrderNum("JD");
+        mallMoneyFlowService.runVipMoneyFlowAdd(
+                memberId,
+                memberId,
+                orderNo,
+                FlowTypeEnum.BALANCE.getValue(),
+                RunVipMoneyFlowTypeEnum.NODE_BALANCE.getValue(),
+                divide,
+                StrUtil.format(RunVipMoneyFlowTypeEnum.NODE_BALANCE.getDescription(),divide),
+                YesOrNoEnum.YES.getValue()
+        );
+
+    }
 }
diff --git a/src/main/java/cc/mrbird/febs/mall/service/impl/MemberProfitServiceImpl.java b/src/main/java/cc/mrbird/febs/mall/service/impl/MemberProfitServiceImpl.java
index ad065f7..c7e69f2 100644
--- a/src/main/java/cc/mrbird/febs/mall/service/impl/MemberProfitServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/mall/service/impl/MemberProfitServiceImpl.java
@@ -51,6 +51,8 @@
     private final MallMemberCouponMapper mallMemberCouponMapper;
     private final RunVipMapper runVipMapper;
     private final MallMemberWalletMapper mallMemberWalletMapper;
+    private final RunNodeSetMapper runNodeSetMapper;
+    private final MallChargeMapper mallChargeMapper;
 
     private final AsyncService asyncService;
 
@@ -688,4 +690,97 @@
             }
         }
     }
+
+    @Override
+    public void updateNodeScore() {
+        /**
+         * 获取全部的节点
+         */
+        List<MallMember> mallMembers = mallMemberMapper.selectList(
+                new LambdaQueryWrapper<MallMember>()
+                        .eq(MallMember::getDirector, YesOrNoEnum.YES.getValue())
+        );
+        if(CollUtil.isEmpty(mallMembers)){
+            return;
+        }
+        //获取节点设置
+        List<RunNodeSet> runNodeSets = runNodeSetMapper.selectList(null);
+        BigDecimal balanceToCoin = new BigDecimal(
+                dataDictionaryCustomMapper.selectDicDataByTypeAndCode(
+                        RunVipDataDictionaryEnum.RUN_VIP_BALANCE_TO_COIN.getType(),
+                        RunVipDataDictionaryEnum.RUN_VIP_BALANCE_TO_COIN.getCode()).getValue()
+        ).setScale(2, BigDecimal.ROUND_DOWN);
+        for (MallMember item : mallMembers) {
+            //获取总业绩
+            BigDecimal achieve = getDirectAchieve(item.getInviteId());
+            BigDecimal nodePercent = getNodePercent(runNodeSets, achieve);
+            asyncService.releaseNodeCoin(achieve,nodePercent,balanceToCoin,item.getId());
+        }
+    }
+
+    private BigDecimal getDirectAchieve(String inviteId) {
+
+        try {
+            // 获取直推成员和团队成员的ID集合
+            Set<Long> memberIds = getTeamMemberIds(inviteId);
+
+            if (CollUtil.isEmpty(memberIds)) {
+                return BigDecimal.ZERO;
+            }
+
+            // 获取团队业绩(不包含本人业绩)
+            List<MallCharge> mallCharges = mallChargeMapper.selectList(
+                    new LambdaQueryWrapper<MallCharge>()
+                            .in(MallCharge::getMemberId, memberIds)
+                            .eq(MallCharge::getState, YesOrNoEnum.YES.getValue())
+            );
+
+            if (CollUtil.isEmpty(mallCharges)) {
+                return BigDecimal.ZERO;
+            }
+
+            return mallCharges.stream()
+                    .map(MallCharge::getAmount)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+        } catch (Exception e) {
+            // 异常处理
+            log.error("Error occurred while calculating direct achieve for member: {}", inviteId, e);
+            return BigDecimal.ZERO;
+        }
+    }
+
+    private Set<Long> getTeamMemberIds(String inviteId) {
+        Set<Long> memberIds = new HashSet<>();
+        // 获取直推成员
+        List<MallMember> directMembers = mallMemberMapper.selectList(
+                new LambdaQueryWrapper<MallMember>()
+                        .eq(MallMember::getReferrerId, inviteId)
+        );
+        memberIds.addAll(directMembers.stream().map(MallMember::getId).collect(Collectors.toSet()));
+
+        // 获取团队成员
+        List<MallMember> teamMembers = mallMemberMapper.selectList(
+                new LambdaQueryWrapper<MallMember>()
+                        .in(MallMember::getReferrerId, directMembers.stream().map(MallMember::getInviteId).collect(Collectors.toSet()))
+        );
+        memberIds.addAll(teamMembers.stream().map(MallMember::getId).collect(Collectors.toSet()));
+
+        return memberIds;
+    }
+
+
+    private BigDecimal getNodePercent(List<RunNodeSet> runNodeSets, BigDecimal directAchieve) {
+        BigDecimal percent = BigDecimal.ZERO;
+        //获取directAchieve在runNodeSets中哪一个位置
+        for(RunNodeSet item : runNodeSets){
+            BigDecimal minAchieve = item.getMinAchieve();
+            BigDecimal maxAchieve = item.getMaxAchieve();
+            BigDecimal nodePercent = new BigDecimal(item.getNodePercent());
+            if(directAchieve.compareTo(minAchieve) >= 0 && directAchieve.compareTo(maxAchieve) < 0){
+                percent = nodePercent;
+                break;
+            }
+        }
+        return percent;
+    }
 }
diff --git a/src/main/resources/templates/febs/views/modules/runVip/nodeAdd.html b/src/main/resources/templates/febs/views/modules/runVip/nodeAdd.html
new file mode 100644
index 0000000..40153a2
--- /dev/null
+++ b/src/main/resources/templates/febs/views/modules/runVip/nodeAdd.html
@@ -0,0 +1,105 @@
+<style>
+    #node-add {
+        padding: 20px 25px 25px 0;
+    }
+
+    #node-add .layui-treeSelect .ztree li a, .ztree li span {
+        margin: 0 0 2px 3px !important;
+    }
+    #node-add #data-permission-tree-block {
+        border: 1px solid #eee;
+        border-radius: 2px;
+        padding: 3px 0;
+    }
+    #node-add .layui-treeSelect .ztree li span.button.switch {
+        top: 1px;
+        left: 3px;
+    }
+    #node-add img{
+        max-width:100px
+    }
+
+</style>
+<div class="layui-fluid" id="febs-node-add">
+    <form class="layui-form" action="" lay-filter="node-add-form">
+        <div class="layui-form-item">
+            <div class="layui-col-lg6">
+                <label class="layui-form-label febs-form-item-require">序号:</label>
+                <div class="layui-input-block">
+                    <input type="number" name="orderNumber" lay-verify="required" autocomplete="off" class="layui-input" >
+                </div>
+            </div>
+
+            <div class="layui-col-lg6">
+                <label class="layui-form-label febs-form-item-require">助力比例:</label>
+                <div class="layui-input-block">
+                    <input type="text" name="nodePercent" lay-verify="required" autocomplete="off" class="layui-input" >
+                </div>
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <div class="layui-col-lg6">
+                <label class="layui-form-label febs-form-item-require">起始业绩:</label>
+                <div class="layui-input-block">
+                    <input type="number" name="minAchieve" lay-verify="required" autocomplete="off" class="layui-input" >
+                </div>
+            </div>
+
+            <div class="layui-col-lg6">
+                <label class="layui-form-label febs-form-item-require">结束业绩:</label>
+                <div class="layui-input-block">
+                    <input type="text" name="maxAchieve" lay-verify="required" autocomplete="off" class="layui-input" >
+                </div>
+            </div>
+        </div>
+
+
+        <div class="layui-form-item febs-hide">
+            <button class="layui-btn" lay-submit="" lay-filter="node-add-form-submit" id="submit"></button>
+        </div>
+    </form>
+</div>
+
+<script data-th-inline="javascript">
+    layui.use(['febs', 'form', 'formSelects', 'validate', 'treeSelect', 'eleTree','layedit', 'laydate', 'upload', 'xmSelect'], function () {
+        var $ = layui.$,
+            febs = layui.febs,
+            layer = layui.layer,
+            upload = layui.upload,
+            formSelects = layui.formSelects,
+            form = layui.form,
+            laydate = layui.laydate,
+            layedit = layui.layedit,
+            $view = $('#node-add'),
+            validate = layui.validate;
+
+        form.render();
+
+        formSelects.render();
+        form.on('submit(node-add-form-submit)', function (data) {
+            $.ajax({
+                'url':ctx + 'admin/runVip/nodeAddOrEdit',
+                'type':'post',
+                'dataType':'json',
+                'headers' : {'Content-Type' : 'application/json;charset=utf-8'}, //接口json格式
+                'traditional': true,//ajax传递数组必须添加属性
+                'data':JSON.stringify(data.field),
+                'success':function (data) {
+                    if(data.code==200){
+                        layer.closeAll();
+                        febs.alert.success(data.message);
+                        $('#febs-run-node').find('#reset').click();
+                    }else{
+                        febs.alert.warn(data.message);
+                    }
+                },
+                'error':function () {
+                    febs.alert.warn('服务器繁忙');
+                }
+            })
+            return false;
+            return false;
+        });
+
+    });
+</script>
\ No newline at end of file
diff --git a/src/main/resources/templates/febs/views/modules/runVip/nodeEdit.html b/src/main/resources/templates/febs/views/modules/runVip/nodeEdit.html
new file mode 100644
index 0000000..72fd712
--- /dev/null
+++ b/src/main/resources/templates/febs/views/modules/runVip/nodeEdit.html
@@ -0,0 +1,111 @@
+<style>
+    #node-edit {
+        padding: 20px 25px 25px 0;
+    }
+
+    #node-edit .layui-treeSelect .ztree li a, .ztree li span {
+        margin: 0 0 2px 3px !important;
+    }
+    #node-edit #data-permission-tree-block {
+        border: 1px solid #eee;
+        border-radius: 2px;
+        padding: 3px 0;
+    }
+    #node-edit .layui-treeSelect .ztree li span.button.switch {
+        top: 1px;
+        left: 3px;
+    }
+    #node-edit img{
+        max-width:100px
+    }
+
+</style>
+<div class="layui-fluid" id="febs-node-edit">
+    <form class="layui-form" action="" lay-filter="node-edit-form">
+        <div class="layui-form-item">
+            <input type="text" name="id" lay-verify="required" autocomplete="off" class="layui-input febs-hide" >
+            <div class="layui-col-lg6">
+                <label class="layui-form-label febs-form-item-require">序号:</label>
+                <div class="layui-input-block">
+                    <input type="number" name="orderNumber" lay-verify="required" autocomplete="off" class="layui-input" >
+                </div>
+            </div>
+
+            <div class="layui-col-lg6">
+                <label class="layui-form-label febs-form-item-require">助力比例:</label>
+                <div class="layui-input-block">
+                    <input type="text" name="nodePercent" lay-verify="required" autocomplete="off" class="layui-input" >
+                </div>
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <div class="layui-col-lg6">
+                <label class="layui-form-label febs-form-item-require">起始业绩:</label>
+                <div class="layui-input-block">
+                    <input type="number" name="minAchieve" lay-verify="required" autocomplete="off" class="layui-input" >
+                </div>
+            </div>
+
+            <div class="layui-col-lg6">
+                <label class="layui-form-label febs-form-item-require">结束业绩:</label>
+                <div class="layui-input-block">
+                    <input type="text" name="maxAchieve" lay-verify="required" autocomplete="off" class="layui-input" >
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item febs-hide">
+            <button class="layui-btn" lay-submit="" lay-filter="node-edit-form-submit" id="submit"></button>
+        </div>
+    </form>
+</div>
+
+<script data-th-inline="javascript">
+    layui.use(['febs', 'form', 'formSelects', 'validate', 'treeSelect', 'eleTree','layedit', 'laydate', 'upload', 'xmSelect'], function () {
+        var $ = layui.$,
+            febs = layui.febs,
+            layer = layui.layer,
+            form = layui.form,
+            $view = $('#node-edit'),
+            runNodeSet = [[${runNodeSet}]]
+            validate = layui.validate;
+
+        form.render();
+        initNodeValue();
+
+        function initNodeValue() {
+            form.val("node-edit-form", {
+                "id": runNodeSet.id,
+                "orderNumber": runNodeSet.orderNumber,
+                "minAchieve" : runNodeSet.minAchieve,
+                "maxAchieve" : runNodeSet.maxAchieve,
+                "nodePercent" : runNodeSet.nodePercent
+            });
+        }
+
+        form.on('submit(node-edit-form-submit)', function (data) {
+            $.ajax({
+                'url':ctx + 'admin/runVip/nodeAddOrEdit',
+                'type':'post',
+                'dataType':'json',
+                'headers' : {'Content-Type' : 'application/json;charset=utf-8'}, //接口json格式
+                'traditional': true,//ajax传递数组必须添加属性
+                'data':JSON.stringify(data.field),
+                'success':function (data) {
+                    if(data.code==200){
+                        layer.closeAll();
+                        febs.alert.success(data.message);
+                        $('#febs-run-node').find('#reset').click();
+                    }else{
+                        febs.alert.warn(data.message);
+                    }
+                },
+                'error':function () {
+                    febs.alert.warn('服务器繁忙');
+                }
+            })
+            return false;
+            return false;
+        });
+    });
+</script>
\ No newline at end of file
diff --git a/src/main/resources/templates/febs/views/modules/runVip/nodeList.html b/src/main/resources/templates/febs/views/modules/runVip/nodeList.html
new file mode 100644
index 0000000..d403a54
--- /dev/null
+++ b/src/main/resources/templates/febs/views/modules/runVip/nodeList.html
@@ -0,0 +1,146 @@
+<div class="layui-fluid layui-anim febs-anim" id="febs-run-node" lay-title="节点规则">
+    <div class="layui-row febs-container">
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-body febs-table-full">
+                    <form class="layui-form layui-table-form" lay-filter="run-node-level-table-form">
+                        <div class="layui-row">
+                            <div class="layui-col-md2 layui-col-sm12 layui-col-xs12 table-action-area">
+                                <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain table-action" id="nodeAdd">
+                                    新增
+                                </div>
+                                <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-blue-plain table-action" id="query">
+                                    <i class="layui-icon">&#xe848;</i>
+                                </div>
+                                <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain table-action" id="reset">
+                                    <i class="layui-icon">&#xe79b;</i>
+                                </div>
+                            </div>
+                        </div>
+                    </form>
+                    <table lay-filter="runNodeLevelTable" lay-data="{id: 'runNodeLevelTable'}"></table>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<style>
+    .layui-table-cell {
+        height: auto;
+    }
+    .layui-form-onswitch {
+        background-color: #5FB878 !important;
+    }
+</style>
+<!-- 表格操作栏 start -->
+<script type="text/html" id="user-option">
+    <span shiro:lacksPermission="runnode:view,runnode:update,runnode:delete">
+        <span class="layui-badge-dot febs-bg-orange"></span> 无权限
+    </span>
+    <a lay-event="edit" shiro:hasPermission="runnode:update"><i
+            class="layui-icon febs-edit-area febs-blue">&#xe7a5;</i></a>
+</script>
+
+<!-- 表格操作栏 end -->
+<script data-th-inline="none" type="text/javascript">
+    // 引入组件并初始化
+    layui.use([ 'jquery', 'form', 'table', 'febs'], function () {
+        var $ = layui.jquery,
+            febs = layui.febs,
+            form = layui.form,
+            table = layui.table,
+            $view = $('#febs-run-node'),
+            $query = $view.find('#query'),
+            $nodeAdd = $view.find('#nodeAdd'),
+            $reset = $view.find('#reset'),
+            $searchForm = $view.find('form'),
+            sortObject = {field: 'orderNumber', type: null},
+            tableIns;
+
+        form.render();
+
+        // 表格初始化
+        initNodeListTable();
+
+        // 初始化表格操作栏各个按钮功能
+        table.on('tool(runNodeLevelTable)', function (obj) {
+            var data = obj.data,
+                layEvent = obj.event;
+            if (layEvent === 'runNodeUpdate') {
+                febs.modal.open('编辑', 'modules/runVip/nodeEdit/' + data.id, {
+                    btn: ['提交', '取消'],
+                    yes: function (index, layero) {
+                        $('#febs-node-edit').find('#submit').trigger('click');
+                    },
+                    btn2: function () {
+                        layer.closeAll();
+                    }
+                });
+            }
+            if (layEvent === 'delRunNode') {
+                febs.modal.confirm('删除', '确认删除?', function () {
+                    delRunNode(data.id);
+                });
+            }
+        });
+
+        function delRunNode(id) {
+            febs.get(ctx + 'admin/runVip/nodeDel/' + id, null, function () {
+                febs.alert.success('操作成功');
+                $query.click();
+            });
+        }
+
+        // 查询按钮
+        $query.on('click', function () {
+            var params = $.extend(getQueryParams(), {field: sortObject.field, order: sortObject.type});
+            tableIns.reload({where: params, page: {curr: 1}});
+        });
+
+        // 刷新按钮
+        $reset.on('click', function () {
+            $searchForm[0].reset();
+            sortObject.type = 'null';
+            tableIns.reload({where: getQueryParams(), page: {curr: 1}, initSort: sortObject});
+        });
+
+        $nodeAdd.on('click', function () {
+            febs.modal.open('新增', 'modules/runVip/nodeAdd/', {
+                btn: ['提交', '取消'],
+                yes: function (index, layero) {
+                    $('#febs-node-add').find('#submit').trigger('click');
+                },
+                btn2: function () {
+                    layer.closeAll();
+                }
+            });
+        });
+
+        function initNodeListTable() {
+            tableIns = febs.table.init({
+                elem: $view.find('table'),
+                id: 'runNodeLevelTable',
+                url: ctx + 'admin/runVip/nodeList',
+                cols: [[
+                    {field: 'orderNumber', title: '序号', minWidth: 120, align: 'center'},
+                    {field: 'minAchieve', title: '业绩范围', minWidth: 120, align: 'center'},
+                    {field: 'maxAchieve', title: '业绩范围', minWidth: 120, align: 'center'},
+                    {field: 'nodePercent', title: '助力比例', minWidth: 120, align: 'center'},
+                    {
+                        title: '操作',
+                        templet: function (d) {
+                            return '<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="runNodeUpdate" shiro:hasPermission="user:update">编辑</button>'
+                                + '<button class="layui-btn layui-btn-danger layui-btn-xs" lay-event="delRunNode" shiro:hasPermission="user:update">删除</button>'
+                        }, minWidth: 300, align: 'center'
+                    }
+                ]]
+            });
+        }
+
+        // 获取查询参数
+        function getQueryParams() {
+            return {
+            };
+        }
+    })
+</script>
\ No newline at end of file
diff --git a/src/main/resources/templates/febs/views/modules/runVip/vipAdd.html b/src/main/resources/templates/febs/views/modules/runVip/vipAdd.html
index 839b9c5..304c5b0 100644
--- a/src/main/resources/templates/febs/views/modules/runVip/vipAdd.html
+++ b/src/main/resources/templates/febs/views/modules/runVip/vipAdd.html
@@ -104,10 +104,10 @@
 
         <div class="layui-form-item">
             <div class="layui-col-lg6">
-                <label class="layui-form-label febs-form-item-require">返利比例:</label>
+                <label class="layui-form-label febs-form-item-require">助力系数:</label>
                 <div class="layui-input-block">
                     <input type="text" name="rebatePercent" lay-verify="required" autocomplete="off" class="layui-input" >
-                    <div class="layui-form-mid layui-word-aux">购买会员返利金额比例(实际支付金额 * rebatePercent = 上级返利金额)。</div>
+                    <div class="layui-form-mid layui-word-aux">助力系数,每日获取的助力值乘以该比例给上级助力。</div>
                 </div>
             </div>
         </div>
diff --git a/src/main/resources/templates/febs/views/modules/runVip/vipEdit.html b/src/main/resources/templates/febs/views/modules/runVip/vipEdit.html
index bbcceba..454e579 100644
--- a/src/main/resources/templates/febs/views/modules/runVip/vipEdit.html
+++ b/src/main/resources/templates/febs/views/modules/runVip/vipEdit.html
@@ -104,10 +104,10 @@
 
         <div class="layui-form-item">
             <div class="layui-col-lg6">
-                <label class="layui-form-label febs-form-item-require">返利比例:</label>
+                <label class="layui-form-label febs-form-item-require">助力系数:</label>
                 <div class="layui-input-block">
                     <input type="text" name="rebatePercent" lay-verify="required" autocomplete="off" class="layui-input" >
-                    <div class="layui-form-mid layui-word-aux">购买会员返利金额比例(实际支付金额 * rebatePercent = 上级返利金额)。</div>
+                    <div class="layui-form-mid layui-word-aux">助力系数,每日获取的助力值乘以该比例给上级助力。</div>
                 </div>
             </div>
         </div>

--
Gitblit v1.9.1