Przeglądaj źródła

update: 营销规则接口调整

lwh 2 tygodni temu
rodzic
commit
6f40e87573

+ 2 - 2
pig-marketing/pig-marketing-api/src/main/java/com/pig4cloud/pig/marketing/api/dto/rule/SaveMktRuleDTO.java

@@ -34,10 +34,10 @@ public class SaveMktRuleDTO implements Serializable {
 	private List<String> keyword;
 
 	@Schema(description = "ip")
-	private String ip;
+	private List<String> ip;
 
 	@Schema(description = "域名")
-	private String domain;
+	private List<String> domain;
 
 	@Schema(description = "推送内容")
 	@NotBlank(message = "推送内容不能为空")

+ 0 - 24
pig-marketing/pig-marketing-api/src/main/java/com/pig4cloud/pig/marketing/api/entity/MktMgmtRule.java

@@ -37,30 +37,6 @@ public class MktMgmtRule extends Model<MktMgmtRule> {
 	@Schema(description = "规则名称")
 	private String ruleName;
 
-	/**
-	 * ip模式
-	 */
-	@Schema(description = "ip模式,1-单IP,2-IP段")
-	private Integer ipMode;
-
-	/**
-	 * 起始IP地址
-	 */
-	@Schema(description = "起始IP地址")
-	private String startIp;
-
-	/**
-	 * 结束IP地址
-	 */
-	@Schema(description = "结束IP地址")
-	private String endIp;
-
-	/**
-	 * 域名
-	 */
-	@Schema(description = "域名")
-	private String domain;
-
 	/**
 	 * 推送内容
 	 */

+ 81 - 0
pig-marketing/pig-marketing-api/src/main/java/com/pig4cloud/pig/marketing/api/entity/MktMgmtRuleDomain.java

@@ -0,0 +1,81 @@
+package com.pig4cloud.pig.marketing.api.entity;
+
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+import java.time.LocalDateTime;
+
+/**
+ * @author: lwh
+ * @date: 2025-09-01
+ * @description: 营销管理规则域名
+ */
+@Data
+@TableName("mkt_mgmt_rule_domain")
+@Schema(description = "营销管理规则域名")
+@EqualsAndHashCode(callSuper = true)
+public class MktMgmtRuleDomain extends Model<MktMgmtRuleDomain> {
+
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * id
+	 */
+	@TableId(value = "id")
+	@Schema(description = "id")
+	private Long id;
+
+	/**
+	 * 规则id
+	 */
+	@Schema(description = "规则id")
+	private Long ruleId;
+
+	/**
+	 * 域名
+	 */
+	@Schema(description = "域名")
+	private String domain;
+
+	/**
+	 * 删除标记
+	 */
+	@TableLogic
+	@TableField(fill = FieldFill.INSERT)
+	@Schema(description = "删除标记,1:已删除,0:正常")
+	private String delFlag;
+
+	/**
+	 * 创建人
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	@Schema(description = "创建人")
+	private String createBy;
+
+	/**
+	 * 修改人
+	 */
+	@TableField(fill = FieldFill.UPDATE)
+	@Schema(description = "修改人")
+	private String updateBy;
+
+	/**
+	 * 创建时间
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	@Schema(description = "创建时间")
+	private LocalDateTime createTime;
+
+	/**
+	 * 更新时间
+	 */
+	@TableField(fill = FieldFill.UPDATE)
+	@Schema(description = "更新时间")
+	private LocalDateTime updateTime;
+}

+ 93 - 0
pig-marketing/pig-marketing-api/src/main/java/com/pig4cloud/pig/marketing/api/entity/MktMgmtRuleIp.java

@@ -0,0 +1,93 @@
+package com.pig4cloud.pig.marketing.api.entity;
+
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+import java.time.LocalDateTime;
+
+/**
+ * @author: lwh
+ * @date: 2025-09-01
+ * @description: 营销管理规则IP
+ */
+@Data
+@TableName("mkt_mgmt_rule_ip")
+@Schema(description = "营销管理规则")
+@EqualsAndHashCode(callSuper = true)
+public class MktMgmtRuleIp extends Model<MktMgmtRuleIp> {
+
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * id
+	 */
+	@TableId(value = "id")
+	@Schema(description = "id")
+	private Long id;
+
+	/**
+	 * 规则id
+	 */
+	@Schema(description = "规则id")
+	private Long ruleId;
+
+	/**
+	 * ip模式
+	 */
+	@Schema(description = "ip模式,1-单IP,2-IP段")
+	private Integer ipMode;
+
+	/**
+	 * 起始IP地址
+	 */
+	@Schema(description = "起始IP地址")
+	private String startIp;
+
+	/**
+	 * 结束IP地址
+	 */
+	@Schema(description = "结束IP地址")
+	private String endIp;
+
+	/**
+	 * 删除标记
+	 */
+	@TableLogic
+	@TableField(fill = FieldFill.INSERT)
+	@Schema(description = "删除标记,1:已删除,0:正常")
+	private String delFlag;
+
+	/**
+	 * 创建人
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	@Schema(description = "创建人")
+	private String createBy;
+
+	/**
+	 * 修改人
+	 */
+	@TableField(fill = FieldFill.UPDATE)
+	@Schema(description = "修改人")
+	private String updateBy;
+
+	/**
+	 * 创建时间
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	@Schema(description = "创建时间")
+	private LocalDateTime createTime;
+
+	/**
+	 * 更新时间
+	 */
+	@TableField(fill = FieldFill.UPDATE)
+	@Schema(description = "更新时间")
+	private LocalDateTime updateTime;
+}

+ 4 - 4
pig-marketing/pig-marketing-api/src/main/java/com/pig4cloud/pig/marketing/api/vo/rule/PageMktRuleVO.java

@@ -38,14 +38,14 @@ public class PageMktRuleVO implements Serializable {
 	/**
 	 * ip
 	 */
-	@Schema(description = "ip")
-	private String ip;
+	@Schema(description = "ip列表")
+	private List<String> ip;
 
 	/**
 	 * 域名
 	 */
-	@Schema(description = "域名")
-	private String domain;
+	@Schema(description = "域名列表")
+	private List<String> domain;
 
 	/**
 	 * 推送内容

+ 15 - 0
pig-marketing/pig-marketing-biz/src/main/java/com/pig4cloud/pig/marketing/mapper/MktMgmtRuleDomainMapper.java

@@ -0,0 +1,15 @@
+package com.pig4cloud.pig.marketing.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pig4cloud.pig.marketing.api.entity.MktMgmtRuleDomain;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @author: lwh
+ * @date: 2025-09-01
+ * @description: 营销管理规则域名Mapper
+ */
+@Mapper
+public interface MktMgmtRuleDomainMapper extends BaseMapper<MktMgmtRuleDomain> {
+}

+ 15 - 0
pig-marketing/pig-marketing-biz/src/main/java/com/pig4cloud/pig/marketing/mapper/MktMgmtRuleIpMapper.java

@@ -0,0 +1,15 @@
+package com.pig4cloud.pig.marketing.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pig4cloud.pig.marketing.api.entity.MktMgmtRuleIp;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @author: lwh
+ * @date: 2025-09-01
+ * @description: 营销管理规则 IP Mapper
+ */
+@Mapper
+public interface MktMgmtRuleIpMapper extends BaseMapper<MktMgmtRuleIp> {
+}

+ 60 - 57
pig-marketing/pig-marketing-biz/src/main/java/com/pig4cloud/pig/marketing/service/impl/MktMgmtPushRecordServiceImpl.java

@@ -1,15 +1,15 @@
 package com.pig4cloud.pig.marketing.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.pig4cloud.pig.marketing.api.dto.MktMgmtPushRecordQueryDTO;
 import com.pig4cloud.pig.marketing.api.dto.MktMgmtPushRecordSaveDTO;
 import com.pig4cloud.pig.marketing.api.entity.MktMgmtKeyword;
 import com.pig4cloud.pig.marketing.api.entity.MktMgmtPushRecord;
 import com.pig4cloud.pig.marketing.api.entity.MktMgmtRule;
-import com.pig4cloud.pig.marketing.mapper.MktMgmtKeywordMapper;
-import com.pig4cloud.pig.marketing.mapper.MktMgmtPushRecordMapper;
-import com.pig4cloud.pig.marketing.mapper.MktMgmtRuleMapper;
+import com.pig4cloud.pig.marketing.api.entity.MktMgmtRuleIp;
+import com.pig4cloud.pig.marketing.mapper.*;
 import com.pig4cloud.pig.marketing.service.MktMgmtPushRecordService;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -32,6 +32,9 @@ public class MktMgmtPushRecordServiceImpl implements MktMgmtPushRecordService {
 	private final MktMgmtKeywordMapper mktMgmtKeywordMapper;
 	private final MktMgmtRuleMapper mktMgmtRuleMapper;
 
+	private final MktMgmtRuleIpMapper mktMgmtRuleIpMapper;
+	private final MktMgmtRuleDomainMapper mktMgmtRuleDomainMapper;
+
 	@Override
 	public Page<MktMgmtPushRecord> pageQuery(MktMgmtPushRecordQueryDTO queryDTO) {
 		log.info("分页查询营销推送记录,查询条件:{}", queryDTO);
@@ -149,73 +152,73 @@ public class MktMgmtPushRecordServiceImpl implements MktMgmtPushRecordService {
 	 * 验证IP地址
 	 */
 	private boolean validateIPAddress(MktMgmtRule rule, String pushIP) {
-		if (rule.getIpMode() == null || rule.getIpMode() == 0) {
-			// IP模式为0-空,不判断IP
-			return true;
-		}
-		
-		if (!StringUtils.hasText(pushIP)) {
-			return false;
-		}
-		
-		if (rule.getIpMode() == 1) {
-			// IP模式为1-单IP,判断推送IP是否为start_ip
-			return pushIP.equals(rule.getStartIp());
-		} else if (rule.getIpMode() == 2) {
-			// IP模式为2-IP段,判断推送IP是否在start_ip和end_ip之间
-			if (!StringUtils.hasText(rule.getStartIp()) || !StringUtils.hasText(rule.getEndIp())) {
-				return false;
-			}
-			
-			try {
-				long pushIpLong = ipToLong(pushIP);
-				long startIpLong = ipToLong(rule.getStartIp());
-				long endIpLong = ipToLong(rule.getEndIp());
-				
-				return pushIpLong >= startIpLong && pushIpLong <= endIpLong;
-			} catch (Exception e) {
-				log.error("IP地址转换异常,pushIP:{},startIp:{},endIp:{}", pushIP, rule.getStartIp(), rule.getEndIp(), e);
-				return false;
-			}
-		}
-		
-		return false;
+//		if (rule.getIpMode() == null || rule.getIpMode() == 0) {
+//			// IP模式为0-空,不判断IP
+//			return true;
+//		}
+//
+//		if (!StringUtils.hasText(pushIP)) {
+//			return false;
+//		}
+//
+//		if (rule.getIpMode() == 1) {
+//			// IP模式为1-单IP,判断推送IP是否为start_ip
+//			return pushIP.equals(rule.getStartIp());
+//		} else if (rule.getIpMode() == 2) {
+//			// IP模式为2-IP段,判断推送IP是否在start_ip和end_ip之间
+//			if (!StringUtils.hasText(rule.getStartIp()) || !StringUtils.hasText(rule.getEndIp())) {
+//				return false;
+//			}
+//
+//			try {
+//				long pushIpLong = ipToLong(pushIP);
+//				long startIpLong = ipToLong(rule.getStartIp());
+//				long endIpLong = ipToLong(rule.getEndIp());
+//
+//				return pushIpLong >= startIpLong && pushIpLong <= endIpLong;
+//			} catch (Exception e) {
+//				log.error("IP地址转换异常,pushIP:{},startIp:{},endIp:{}", pushIP, rule.getStartIp(), rule.getEndIp(), e);
+//				return false;
+//			}
+//		}
+		
+		return true;
 	}
 	
 	/**
 	 * 验证域名
 	 */
 	private boolean validateDomain(MktMgmtRule rule, String pushDomain) {
-		// 如果规则中域名为空,则不判断域名
-		if (!StringUtils.hasText(rule.getDomain())) {
-			return true;
-		}
-		
-		// 如果推送域名为空,则验证失败
-		if (!StringUtils.hasText(pushDomain)) {
-			return false;
-		}
-		
-		// 判断推送域名是否为规则的域名
-		return rule.getDomain().equals(pushDomain);
+//		// 如果规则中域名为空,则不判断域名
+//		if (!StringUtils.hasText(rule.getDomain())) {
+//			return true;
+//		}
+//
+//		// 如果推送域名为空,则验证失败
+//		if (!StringUtils.hasText(pushDomain)) {
+//			return false;
+//		}
+//
+//		// 判断推送域名是否为规则的域名
+//		return rule.getDomain().equals(pushDomain);
+		return true;
 	}
-	
 	/**
 	 * 构建触发条件描述
 	 */
 	private String buildTriggerCondition(String keyword, MktMgmtRule rule, String pushIP, String pushDomain) {
 		StringBuilder triggerCondition = new StringBuilder();
 		triggerCondition.append("关键字:").append(keyword);
-		
-		// 添加IP信息
-		if (rule.getIpMode() != null && rule.getIpMode() > 0 && StringUtils.hasText(pushIP)) {
-			triggerCondition.append(",IP:").append(pushIP);
-		}
-		
-		// 添加域名信息
-		if (StringUtils.hasText(rule.getDomain()) && StringUtils.hasText(pushDomain)) {
-			triggerCondition.append(",域名:").append(pushDomain);
-		}
+//
+//		// 添加IP信息
+//		if (rule.getIpMode() != null && rule.getIpMode() > 0 && StringUtils.hasText(pushIP)) {
+//			triggerCondition.append(",IP:").append(pushIP);
+//		}
+//
+//		// 添加域名信息
+//		if (StringUtils.hasText(rule.getDomain()) && StringUtils.hasText(pushDomain)) {
+//			triggerCondition.append(",域名:").append(pushDomain);
+//		}
 		
 		return triggerCondition.toString();
 	}

+ 520 - 83
pig-marketing/pig-marketing-biz/src/main/java/com/pig4cloud/pig/marketing/service/impl/MktMgmtRuleServiceImpl.java

@@ -1,6 +1,7 @@
 package com.pig4cloud.pig.marketing.service.impl;
 
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -10,9 +11,13 @@ import com.pig4cloud.pig.marketing.api.dto.rule.PageMktRuleDTO;
 import com.pig4cloud.pig.marketing.api.dto.rule.SaveMktRuleDTO;
 import com.pig4cloud.pig.marketing.api.entity.MktMgmtKeyword;
 import com.pig4cloud.pig.marketing.api.entity.MktMgmtRule;
+import com.pig4cloud.pig.marketing.api.entity.MktMgmtRuleDomain;
+import com.pig4cloud.pig.marketing.api.entity.MktMgmtRuleIp;
 import com.pig4cloud.pig.marketing.api.util.DomainValidationUtil;
 import com.pig4cloud.pig.marketing.api.vo.rule.PageMktRuleVO;
 import com.pig4cloud.pig.marketing.mapper.MktMgmtKeywordMapper;
+import com.pig4cloud.pig.marketing.mapper.MktMgmtRuleDomainMapper;
+import com.pig4cloud.pig.marketing.mapper.MktMgmtRuleIpMapper;
 import com.pig4cloud.pig.marketing.mapper.MktMgmtRuleMapper;
 import com.pig4cloud.pig.marketing.service.MktMgmtRuleService;
 import lombok.AllArgsConstructor;
@@ -23,10 +28,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
 
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -43,90 +45,95 @@ public class MktMgmtRuleServiceImpl implements MktMgmtRuleService {
 
 	private final MktMgmtKeywordMapper mktMgmtKeywordMapper;
 
+	private final MktMgmtRuleIpMapper mktMgmtRuleIpMapper;
+
+	private final MktMgmtRuleDomainMapper mktMgmtRuleDomainMapper;
+
 	/**
 	 * 保存/修改营销规则
 	 * @param reqDto 入参
 	 */
 	@Override
 	@Transactional
-	public void saveMktRule(SaveMktRuleDTO reqDto) {
-		// 处理IP格式解析
-		String ip = reqDto.getIp();
-		int ipMode = 0;
-		String startIp = null;
-		String endIp = null;
-
-		// 处理IP格式
-		if (StringUtils.hasText(ip)) {
-			// 检查是否为IP段格式(包含"/")
-			if (ip.contains("/")) {
-				// IP段格式:192.168.1.1/10
-				String[] parts = ip.split("/");
-				if (parts.length == 2) {
-					String startIpPart = parts[0];
-					String endIpSuffix = parts[1];
-					// 验证起始IP格式
-					if (!IPUtils.isValidIp(startIpPart)) {
-						throw new BusinessException("起始IP格式不正确");
-					}
-					// 计算结束IP
-					try {
-						// 解析起始IP
-						String[] startParts = startIpPart.split("\\.");
-						if (startParts.length == 4) {
+	public void saveMktRule(SaveMktRuleDTO reqDto){
+		// 验证IP列表
+		List<String> ipList = reqDto.getIp();
+		// 验证域名列表
+		List<String> domainList = reqDto.getDomain();
+
+		if (reqDto.getId() == null) {
+			// 新增规则
+			MktMgmtRule rule = new MktMgmtRule();
+			BeanUtils.copyProperties(reqDto, rule);
+			mktMgmtRuleMapper.insert(rule);
+
+			// 保存IP列表
+			if (ipList != null && !ipList.isEmpty()) {
+				for (String ip : ipList) {
+					if (StringUtils.hasText(ip)) {
+						MktMgmtRuleIp ruleIp = new MktMgmtRuleIp();
+						ruleIp.setRuleId(rule.getId());
+
+						// 处理IP格式
+						if (ip.contains("/")) {
+							// IP段格式
+							String[] parts = ip.split("/");
+							String startIp = parts[0];
+							String endIpSuffix = parts[1];
+
+							String[] startParts = startIp.split("\\.");
 							int endSuffix = Integer.parseInt(endIpSuffix);
-							// 构建结束IP,保持前三段不变
-							endIp = String.format("%s.%s.%s.%d",
+							String endIp = String.format("%s.%s.%s.%d",
 									startParts[0], startParts[1], startParts[2], endSuffix);
-							startIp = startIpPart;
-							ipMode = 2; // IP段模式
+
+							ruleIp.setIpMode(2); // IP段模式
+							ruleIp.setStartIp(startIp);
+							ruleIp.setEndIp(endIp);
+						} else {
+							// 单IP格式
+							ruleIp.setIpMode(1);
+							ruleIp.setStartIp(ip);
+							ruleIp.setEndIp("");
 						}
-					} catch (NumberFormatException e) {
-						throw new BusinessException("IP段格式不正确");
+						// 校验IP合法性
+						validateIp(ruleIp);
+						mktMgmtRuleIpMapper.insert(ruleIp);
 					}
-					if (endIp == null) {
-						throw new BusinessException("IP段格式不正确");
-					}
-				} else {
-					throw new BusinessException("IP段格式不正确,应为:起始IP/结束IP后缀");
-				}
-			} else {
-				// 单IP格式
-				if (!IPUtils.isValidIp(ip)) {
-					throw new BusinessException("IP格式不正确");
 				}
-				// 设置IP相关字段
-				ipMode = 1;
-				startIp = ip;
-			}
-		}
-		// 验证域名
-		if (StringUtils.hasText(reqDto.getDomain())){
-			if (!DomainValidationUtil.isValidDomain(reqDto.getDomain())){
-				throw new BusinessException("域名格式错误");
 			}
-		}
 
-		if (reqDto.getId() == null) {
-			// 新增规则
-			MktMgmtRule rule = new MktMgmtRule();
-			BeanUtils.copyProperties(reqDto, rule);
-			// 设置IP相关字段
-			rule.setIpMode(ipMode);
-			rule.setStartIp(startIp == null ? "" : startIp);
-			rule.setEndIp(endIp == null ? "" : endIp);
-			mktMgmtRuleMapper.insert(rule);
+			// 保存域名列表
+			if (domainList != null && !domainList.isEmpty()) {
+				for (String domain : domainList) {
+					if (StringUtils.hasText(domain)) {
+						// 校验域名
+						validateDomain(domain);
+						MktMgmtRuleDomain ruleDomain = new MktMgmtRuleDomain();
+						ruleDomain.setRuleId(rule.getId());
+						ruleDomain.setDomain(domain);
+						mktMgmtRuleDomainMapper.insert(ruleDomain);
+					}
+				}
+			}
 
 			// 保存关键字
 			List<String> keywords = reqDto.getKeyword();
+			if (keywords != null && !keywords.isEmpty()) {
+				for (String keyword : keywords) {
+					if (StringUtils.hasText(keyword)) {
+						if (checkRuleKeywordExists(keyword)) {
+							throw new BusinessException("关键字 '" + keyword + "' 已存在,不能重复");
+						}
 
-			for (String keyword : keywords) {
-				MktMgmtKeyword mktMgmtKeyword = new MktMgmtKeyword();
-				mktMgmtKeyword.setKeyword(keyword);
-				mktMgmtKeyword.setRuleId(rule.getId());
-				mktMgmtKeywordMapper.insert(mktMgmtKeyword);
+						MktMgmtKeyword mktMgmtKeyword = new MktMgmtKeyword();
+						mktMgmtKeyword.setKeyword(keyword);
+						mktMgmtKeyword.setRuleId(rule.getId());
+						mktMgmtKeywordMapper.insert(mktMgmtKeyword);
+					}
+				}
 			}
-		}else {
+		}
+		else {
 			// 1. 更新主规则信息
 			MktMgmtRule mktMgmtRule = mktMgmtRuleMapper.selectById(reqDto.getId());
 			if (mktMgmtRule == null) {
@@ -134,14 +141,132 @@ public class MktMgmtRuleServiceImpl implements MktMgmtRuleService {
 			}
 			MktMgmtRule rule = new MktMgmtRule();
 			BeanUtils.copyProperties(reqDto, rule);
-			// 设置IP相关字段
-			rule.setIpMode(ipMode);
-			rule.setStartIp(startIp == null ? "" : startIp);
-			rule.setEndIp(endIp == null ? "" : endIp);
 			mktMgmtRuleMapper.updateById(rule);
 
-			// 2. 处理关键字(先删除旧的,再添加新的)
+			// 2. 处理IP列表
 			Long ruleId = reqDto.getId();
+
+			// 查询现有的IP记录
+			List<MktMgmtRuleIp> oldIpRecords = mktMgmtRuleIpMapper.selectList(Wrappers.<MktMgmtRuleIp>lambdaQuery()
+					.eq(MktMgmtRuleIp::getRuleId, ruleId));
+
+			// 构建现有IP的映射(startIp -> record)
+			Map<String, MktMgmtRuleIp> oldIpMap = oldIpRecords.stream()
+					.collect(Collectors.toMap(MktMgmtRuleIp::getStartIp, ip -> ip));
+
+			// 构建新IP的映射
+			Map<String, MktMgmtRuleIp> newIpMap = new HashMap<>();
+			if (ipList != null && !ipList.isEmpty()) {
+				for (String ip : ipList) {
+					if (StringUtils.hasText(ip)) {
+						MktMgmtRuleIp ruleIp = new MktMgmtRuleIp();
+						ruleIp.setRuleId(ruleId);
+
+						// 处理IP格式
+						if (ip.contains("/")) {
+							// IP段格式
+							String[] parts = ip.split("/");
+							String startIpPart = parts[0];
+							String endIpSuffix = parts[1];
+
+							String[] startParts = startIpPart.split("\\.");
+							int endSuffix = Integer.parseInt(endIpSuffix);
+							String endIp = String.format("%s.%s.%s.%d",
+									startParts[0], startParts[1], startParts[2], endSuffix);
+
+							ruleIp.setIpMode(2); // IP段模式
+							ruleIp.setStartIp(startIpPart);
+							ruleIp.setEndIp(endIp);
+						} else {
+							// 单IP格式
+							ruleIp.setIpMode(1);
+							ruleIp.setStartIp(ip);
+							ruleIp.setEndIp("");
+						}
+
+						newIpMap.put(ruleIp.getStartIp(), ruleIp);
+					}
+				}
+			}
+
+			// 处理需要删除的IP(存在于旧列表但不存在于新列表)
+			List<Long> needDeleteIpIds = oldIpRecords.stream()
+					.filter(oldIp -> !newIpMap.containsKey(oldIp.getStartIp()))
+					.map(MktMgmtRuleIp::getId)
+					.toList();
+			if (!needDeleteIpIds.isEmpty()) {
+				mktMgmtRuleIpMapper.deleteByIds(needDeleteIpIds);
+			}
+
+			// 处理需要新增的IP(存在于新列表但不存在于旧列表)
+			List<MktMgmtRuleIp> needAddIps = newIpMap.values().stream()
+					.filter(newIp -> !oldIpMap.containsKey(newIp.getStartIp()))
+					.toList();
+			if (!needAddIps.isEmpty()) {
+				for (MktMgmtRuleIp ruleIp : needAddIps) {
+					// 校验IP合法性
+					validateIp(ruleIp);
+					// 校验IP是否已存在
+					if (checkRuleIpExists(ruleIp, ruleId)) {
+						if (ruleIp.getIpMode() == 1) {
+							throw new BusinessException("IP '" + ruleIp.getStartIp() + "' 已存在或被其他IP段包含");
+						} else {
+							String[] end = ruleIp.getEndIp().split("\\.");
+							throw new BusinessException("IP段 '" + ruleIp.getStartIp() + "/" + end[3] + "' 已存在或与其他IP段重叠");
+						}
+					}
+					mktMgmtRuleIpMapper.insert(ruleIp);
+				}
+			}
+
+			// 3. 处理域名列表
+			// 查询现有的域名记录
+			List<MktMgmtRuleDomain> oldDomainRecords = mktMgmtRuleDomainMapper.selectList(Wrappers.<MktMgmtRuleDomain>lambdaQuery()
+					.eq(MktMgmtRuleDomain::getRuleId, ruleId));
+
+			// 构建现有域名的映射(domain -> record)
+			Map<String, MktMgmtRuleDomain> oldDomainMap = oldDomainRecords.stream()
+					.collect(Collectors.toMap(MktMgmtRuleDomain::getDomain, domain -> domain));
+
+			// 构建新域名的映射
+			Map<String, MktMgmtRuleDomain> newDomainMap = new HashMap<>();
+			if (domainList != null && !domainList.isEmpty()) {
+				for (String domain : domainList) {
+					if (StringUtils.hasText(domain)) {
+						MktMgmtRuleDomain ruleDomain = new MktMgmtRuleDomain();
+						ruleDomain.setRuleId(ruleId);
+						ruleDomain.setDomain(domain);
+						newDomainMap.put(domain, ruleDomain);
+					}
+				}
+			}
+
+			// 处理需要删除的域名(存在于旧列表但不存在于新列表)
+			List<Long> needDeleteDomainIds = oldDomainRecords.stream()
+					.filter(oldDomain -> !newDomainMap.containsKey(oldDomain.getDomain()))
+					.map(MktMgmtRuleDomain::getId)
+					.toList();
+			if (!needDeleteDomainIds.isEmpty()) {
+				mktMgmtRuleDomainMapper.deleteByIds(needDeleteDomainIds);
+			}
+
+			// 处理需要新增的域名(存在于新列表但不存在于旧列表)
+			List<MktMgmtRuleDomain> needAddDomains = newDomainMap.values().stream()
+					.filter(newDomain -> !oldDomainMap.containsKey(newDomain.getDomain()))
+					.toList();
+			if (!needAddDomains.isEmpty()) {
+				for (MktMgmtRuleDomain ruleDomain : needAddDomains) {
+					// 校验域名合法性
+					validateDomain(ruleDomain.getDomain());
+					// 校验新增的域名是否重复
+					if (checkRuleDomainExists(ruleDomain.getDomain(), ruleId)) {
+						throw new BusinessException("域名 '" + ruleDomain.getDomain() + "' 已存在,不能重复");
+					}
+					mktMgmtRuleDomainMapper.insert(ruleDomain);
+				}
+			}
+
+			// 4. 处理关键字(精确更新)
 			List<String> newKeywords = reqDto.getKeyword();
 			newKeywords = newKeywords == null ? Collections.emptyList() : newKeywords;
 
@@ -151,10 +276,10 @@ public class MktMgmtRuleServiceImpl implements MktMgmtRuleService {
 					.map(MktMgmtKeyword::getKeyword)
 					.collect(Collectors.toSet());
 
-			// 2. 提取新关键字集合
+			// 提取新关键字集合
 			Set<String> newKeywordSet = new HashSet<>(newKeywords);
 
-			// 3. 处理需要删除的关键字
+			// 处理需要删除的关键字(存在于旧列表但不存在于新列表)
 			List<Long> needDeleteIds = oldKeywords.stream()
 					.filter(keyword -> !newKeywordSet.contains(keyword.getKeyword()))
 					.map(MktMgmtKeyword::getId)
@@ -162,12 +287,18 @@ public class MktMgmtRuleServiceImpl implements MktMgmtRuleService {
 			if (!needDeleteIds.isEmpty()) {
 				mktMgmtKeywordMapper.deleteByIds(needDeleteIds);
 			}
-			// 4. 处理需要新增的关键字(存在于新列表但不存在于旧列表)
+
+			// 处理需要新增的关键字(存在于新列表但不存在于旧列表)
 			List<String> needAddKeywords = newKeywordSet.stream()
 					.filter(keyword -> !oldKeywordSet.contains(keyword))
 					.toList();
 			if (!needAddKeywords.isEmpty()) {
 				for (String keyword : needAddKeywords) {
+					// 检查关键字是否重复
+					if (checkRuleKeywordExists(keyword)) {
+						throw new BusinessException("关键字 '" + keyword + "' 已被其他规则使用,不能重复");
+					}
+
 					MktMgmtKeyword mktMgmtKeyword = new MktMgmtKeyword();
 					mktMgmtKeyword.setKeyword(keyword);
 					mktMgmtKeyword.setRuleId(ruleId);
@@ -175,7 +306,6 @@ public class MktMgmtRuleServiceImpl implements MktMgmtRuleService {
 				}
 			}
 		}
-
 	}
 
 	/**
@@ -186,11 +316,14 @@ public class MktMgmtRuleServiceImpl implements MktMgmtRuleService {
 	@Override
 	@Transactional
 	public Boolean delMktRuleByIds(@ParameterObject List<Long> ids) {
-		int i = mktMgmtRuleMapper.deleteByIds(ids);
-		int delete = mktMgmtKeywordMapper.delete(Wrappers.<MktMgmtKeyword>lambdaQuery()
+		int delRule = mktMgmtRuleMapper.deleteByIds(ids);
+		int delKeyword = mktMgmtKeywordMapper.delete(Wrappers.<MktMgmtKeyword>lambdaQuery()
 				.in(MktMgmtKeyword::getRuleId, ids));
-
-		return i > 0 && delete > 0;
+		int delIp = mktMgmtRuleIpMapper.delete(Wrappers.<MktMgmtRuleIp>lambdaQuery()
+				.in(MktMgmtRuleIp::getRuleId, ids));
+		int delDomain = mktMgmtRuleDomainMapper.delete(Wrappers.<MktMgmtRuleDomain>lambdaQuery()
+				.in(MktMgmtRuleDomain::getRuleId, ids));
+		return delRule > 0 && delKeyword > 0 && delIp > 0 && delDomain > 0;
 	}
 
 	/**
@@ -225,6 +358,154 @@ public class MktMgmtRuleServiceImpl implements MktMgmtRuleService {
 			}
 		}
 
+		// 1.2、IP匹配逻辑 - 从IP规则表中查询
+		if (StringUtils.hasText(reqDto.getIp())) {
+			String inputIp = reqDto.getIp();
+			// 验证输入IP格式
+			if (!IPUtils.isValidIp(inputIp)) {
+				throw new BusinessException("输入的IP格式不正确");
+			}
+
+			// 查询匹配IP的规则ID列表
+			List<MktMgmtRuleIp> ipRules = mktMgmtRuleIpMapper.selectList(
+					Wrappers.<MktMgmtRuleIp>lambdaQuery()
+							.and(wrapper -> wrapper
+									// 匹配单IP模式:ipMode=1 且 startIp等于输入IP
+									.and(w -> w.eq(MktMgmtRuleIp::getIpMode, 1)
+											.eq(MktMgmtRuleIp::getStartIp, inputIp))
+									// 匹配IP段模式:ipMode=2 且 输入IP在startIp和endIp范围内
+									.or(w -> w.eq(MktMgmtRuleIp::getIpMode, 2)
+											.apply("INET_ATON({0}) BETWEEN INET_ATON(start_ip) AND INET_ATON(end_ip)", inputIp))
+							)
+			);
+
+			if (!ipRules.isEmpty()) {
+				List<Long> ruleIds = ipRules.stream()
+						.map(MktMgmtRuleIp::getRuleId)
+						.distinct()
+						.collect(Collectors.toList());
+				queryWrapper.in("id", ruleIds);
+			} else {
+				// 如果没有找到匹配的IP规则,返回空结果
+				return new Page<>();
+			}
+		}
+
+		// 1.3、域名模糊查询 - 从域名规则表中查询
+		if (StringUtils.hasText(reqDto.getDomain())) {
+			// 查询匹配域名的规则ID列表
+			List<MktMgmtRuleDomain> domainRules = mktMgmtRuleDomainMapper.selectList(
+					Wrappers.<MktMgmtRuleDomain>lambdaQuery()
+							.like(MktMgmtRuleDomain::getDomain, reqDto.getDomain())
+			);
+
+			if (!domainRules.isEmpty()) {
+				List<Long> ruleIds = domainRules.stream()
+						.map(MktMgmtRuleDomain::getRuleId)
+						.distinct()
+						.collect(Collectors.toList());
+				queryWrapper.in("id", ruleIds);
+			} else {
+				// 如果没有找到匹配的域名规则,返回空结果
+				return new Page<>();
+			}
+		}
+
+		// 按创建时间倒序排列
+		queryWrapper.orderByDesc("create_time");
+
+		// 执行分页查询
+		Page<MktMgmtRule> rulePage = mktMgmtRuleMapper.selectPage(page, queryWrapper);
+
+		// 转换为VO对象
+		Page<PageMktRuleVO> resultPage = new Page<>(reqDto.getCurrent(), reqDto.getSize());
+		resultPage.setTotal(rulePage.getTotal());
+		resultPage.setPages(rulePage.getPages());
+
+		List<PageMktRuleVO> voList = rulePage.getRecords().stream().map(rule -> {
+			PageMktRuleVO vo = new PageMktRuleVO();
+			BeanUtils.copyProperties(rule, vo);
+
+			// 查询该规则对应的关键字列表
+			List<MktMgmtKeyword> keywords = mktMgmtKeywordMapper.selectList(
+					Wrappers.<MktMgmtKeyword>lambdaQuery()
+							.eq(MktMgmtKeyword::getRuleId, rule.getId())
+			);
+
+			List<String> keywordList = keywords.stream()
+					.map(MktMgmtKeyword::getKeyword)
+					.collect(Collectors.toList());
+			vo.setKeyword(keywordList);
+
+			// 查询该规则对应的IP列表
+			List<MktMgmtRuleIp> ipRules = mktMgmtRuleIpMapper.selectList(
+					Wrappers.<MktMgmtRuleIp>lambdaQuery()
+							.eq(MktMgmtRuleIp::getRuleId, rule.getId())
+			);
+
+			List<String> ipList = ipRules.stream().map(ipRule -> {
+				if (ipRule.getIpMode() == 1) {
+					// 单IP模式
+					return ipRule.getStartIp();
+				} else {
+					// IP段模式:从endIP中提取最后一段作为后缀
+					String startIp = ipRule.getStartIp();
+					String endIp = ipRule.getEndIp();
+
+					// 提取endIP的最后一段
+					String[] endParts = endIp.split("\\.");
+					String endSuffix = endParts[endParts.length - 1];
+
+					return startIp + "/" + endSuffix;
+				}
+			}).collect(Collectors.toList());
+			vo.setIp(ipList);
+
+			// 查询该规则对应的域名列表
+			List<MktMgmtRuleDomain> domainRules = mktMgmtRuleDomainMapper.selectList(
+					Wrappers.<MktMgmtRuleDomain>lambdaQuery()
+							.eq(MktMgmtRuleDomain::getRuleId, rule.getId())
+			);
+
+			List<String> domainList = domainRules.stream()
+					.map(MktMgmtRuleDomain::getDomain)
+					.collect(Collectors.toList());
+			vo.setDomain(domainList);
+
+			return vo;
+		}).collect(Collectors.toList());
+
+		resultPage.setRecords(voList);
+
+		return resultPage;
+	}
+
+	public Page<PageMktRuleVO> pageMktRule2(PageMktRuleDTO reqDto) {
+		Page<MktMgmtRule> page = new Page<>(reqDto.getCurrent(), reqDto.getSize());
+
+		// 构建查询条件
+		QueryWrapper<MktMgmtRule> queryWrapper = new QueryWrapper<>();
+
+		// 1.1、关键字模糊查询 - 通过关联查询关键字表
+		if (StringUtils.hasText(reqDto.getKeyword())) {
+			// 先查询包含该关键字的规则ID
+			List<MktMgmtKeyword> keywords = mktMgmtKeywordMapper.selectList(
+					Wrappers.<MktMgmtKeyword>lambdaQuery()
+							.like(MktMgmtKeyword::getKeyword, reqDto.getKeyword())
+			);
+
+			if (!keywords.isEmpty()) {
+				List<Long> ruleIds = keywords.stream()
+						.map(MktMgmtKeyword::getRuleId)
+						.distinct()
+						.collect(Collectors.toList());
+				queryWrapper.in("id", ruleIds);
+			} else {
+				// 如果没有找到匹配的关键字,返回空结果
+				return new Page<>();
+			}
+		}
+
 		// 1.2、IP匹配逻辑 - 支持单IP和IP段匹配
 		if (StringUtils.hasText(reqDto.getIp())) {
 			String inputIp = reqDto.getIp();
@@ -294,6 +575,61 @@ public class MktMgmtRuleServiceImpl implements MktMgmtRuleService {
 		}
 		PageMktRuleVO result = new PageMktRuleVO();
 		BeanUtils.copyProperties(mktMgmtRule, result);
+
+		// 查询该规则对应的关键字列表
+		List<MktMgmtKeyword> keywords = mktMgmtKeywordMapper.selectList(
+				Wrappers.<MktMgmtKeyword>lambdaQuery()
+						.eq(MktMgmtKeyword::getRuleId, id)
+		);
+		List<String> keywordList = keywords.stream()
+				.map(MktMgmtKeyword::getKeyword)
+				.collect(Collectors.toList());
+		result.setKeyword(keywordList);
+
+		// 查询该规则对应的IP列表
+		List<MktMgmtRuleIp> ipRules = mktMgmtRuleIpMapper.selectList(
+				Wrappers.<MktMgmtRuleIp>lambdaQuery()
+						.eq(MktMgmtRuleIp::getRuleId, id)
+		);
+
+		List<String> ipList = ipRules.stream().map(ipRule -> {
+			if (ipRule.getIpMode() == 1) {
+				// 单IP模式
+				return ipRule.getStartIp();
+			} else {
+				// IP段模式:从endIP中提取最后一段作为后缀
+				String startIp = ipRule.getStartIp();
+				String endIp = ipRule.getEndIp();
+
+				// 提取endIP的最后一段
+				String[] endParts = endIp.split("\\.");
+				String endSuffix = endParts[endParts.length - 1];
+
+				return startIp + "/" + endSuffix;
+			}
+		}).collect(Collectors.toList());
+		result.setIp(ipList);
+
+		// 查询该规则对应的域名列表
+		List<MktMgmtRuleDomain> domainRules = mktMgmtRuleDomainMapper.selectList(
+				Wrappers.<MktMgmtRuleDomain>lambdaQuery()
+						.eq(MktMgmtRuleDomain::getRuleId, id)
+		);
+
+		List<String> domainList = domainRules.stream()
+				.map(MktMgmtRuleDomain::getDomain)
+				.collect(Collectors.toList());
+		result.setDomain(domainList);
+
+		return result;
+	}
+	public PageMktRuleVO getMktRuleById2(Long id) {
+		MktMgmtRule mktMgmtRule = mktMgmtRuleMapper.selectById(id);
+		if (mktMgmtRule == null){
+			throw new BusinessException("规则不存在");
+		}
+		PageMktRuleVO result = new PageMktRuleVO();
+		BeanUtils.copyProperties(mktMgmtRule, result);
 		// 查询该规则对应关键字列表
 		List<MktMgmtKeyword> keywords = mktMgmtKeywordMapper.selectList(Wrappers.<MktMgmtKeyword>lambdaQuery()
 				.eq(MktMgmtKeyword::getRuleId, id));
@@ -303,4 +639,105 @@ public class MktMgmtRuleServiceImpl implements MktMgmtRuleService {
 		result.setKeyword(keywordList);
 		return result;
 	}
+
+	/**
+	 * 校验IP格式是否合法
+	 * @param ruleIp IP信息
+	 */
+	private void validateIp(MktMgmtRuleIp ruleIp){
+		if (!IPUtils.isValidIp(ruleIp.getStartIp())){
+			throw new BusinessException("start ip 格式不合法(IPv4)");
+		}
+		if (ruleIp.getIpMode() == 2){
+			if (!IPUtils.isValidIp(ruleIp.getEndIp())){
+				throw new BusinessException("end ip 格式不合法(IPv4)");
+			}
+			if (!IPUtils.isEndIpGreater(ruleIp.getStartIp(), ruleIp.getEndIp())){
+				throw new BusinessException("结束IP不能小于开始IP");
+			}
+		}
+	}
+
+	/**
+	 * 校验域名格式是否合法
+	 * @param domain 域名
+	 */
+	private void validateDomain(String domain){
+		if (!DomainValidationUtil.isValidDomain(domain)) {
+			throw new BusinessException("域名格式错误: " + domain);
+		}
+	}
+
+	/**
+	 * 检查规则IP是否重复
+	 * @param ruleIp 要检查的IP信息
+	 * @param ruleId 规则ID(更新时使用,新增时为null)
+	 * @return 是否存在重复
+	 */
+	private Boolean checkRuleIpExists(MktMgmtRuleIp ruleIp, Long ruleId){
+		QueryWrapper<MktMgmtRuleIp> query = new QueryWrapper<MktMgmtRuleIp>().eq("rule_id", ruleId);
+
+		query.and(wrapper -> {
+			// 单IP模式检查
+			if (ruleIp.getIpMode() == 1) {
+				String targetIp = ruleIp.getStartIp();
+				// 检查是否有相同单IP
+				wrapper.and(w -> w
+						.eq("ip_mode", 1)
+						.eq("start_ip", targetIp));
+
+				// 检查是否被IP段包含
+				wrapper.or(w -> w
+						.eq("ip_mode", 2)
+						.apply("INET_ATON({0}) BETWEEN INET_ATON(start_ip) AND INET_ATON(end_ip)", targetIp));
+			}
+
+			// IP段模式检查
+			if (ruleIp.getIpMode() == 2) {
+				String startIp = ruleIp.getStartIp();
+				String endIp = ruleIp.getEndIp();
+
+				// 检查是否与单IP重叠:单IP在输入IP段范围内
+				wrapper.and(w -> w
+						.eq("ip_mode", 1)
+						.apply("INET_ATON(start_ip) BETWEEN INET_ATON({0}) AND INET_ATON({1})", startIp, endIp));
+
+				// 检查是否与IP段重叠:两个IP段有交集
+				wrapper.or(w -> w
+						.eq("ip_mode", 2)
+						.and(w2 -> w2
+								.apply("INET_ATON(start_ip) BETWEEN INET_ATON({0}) AND INET_ATON({1})", startIp, endIp)
+								.or().apply("INET_ATON(end_ip) BETWEEN INET_ATON({0}) AND INET_ATON({1})", startIp, endIp)
+								.or().apply("INET_ATON({0}) BETWEEN INET_ATON(start_ip) AND INET_ATON(end_ip)", startIp)
+						)
+				);
+			}
+		});
+
+		return mktMgmtRuleIpMapper.selectCount(query) > 0;
+	}
+
+	/**
+	 * 检查规则域名是否存在重复
+	 * @param domain 要检查的域名
+	 * @param ruleId 规则ID(更新时使用,新增时为null)
+	 * @return 是否存在重复
+	 */
+	private Boolean checkRuleDomainExists(String domain, Long ruleId) {
+		LambdaQueryWrapper<MktMgmtRuleDomain> wrapper = Wrappers.<MktMgmtRuleDomain>lambdaQuery()
+				.eq(MktMgmtRuleDomain::getDomain, domain)
+				.ne(MktMgmtRuleDomain::getRuleId, ruleId);
+		return mktMgmtRuleDomainMapper.selectCount(wrapper) > 0;
+	}
+
+	/**
+	 * 检查规则关键则是否存在重复
+	 * @param keyword 要检查的域名
+	 * @return 是否存在重复
+	 */
+	private Boolean checkRuleKeywordExists(String keyword){
+		LambdaQueryWrapper<MktMgmtKeyword> wrapper = Wrappers.<MktMgmtKeyword>lambdaQuery()
+				.eq(MktMgmtKeyword::getKeyword, keyword);
+		return mktMgmtKeywordMapper.selectCount(wrapper) > 0;
+	}
 }