9
0

2 Commits 7819955e04 ... cc6c1f2f31

Autor SHA1 Nachricht Datum
  YPZ cc6c1f2f31 Merge remote-tracking branch 'origin/master' vor 1 Woche
  YPZ 0727d6947b 营销sop提交 vor 1 Woche
23 geänderte Dateien mit 795 neuen und 84 gelöschten Zeilen
  1. 56 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/controller/MarketingController.java
  2. 156 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/controller/SopController.java
  3. 25 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/dto/MarketingCampaignDTO.java
  4. 25 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/dto/SopCreateDTO.java
  5. 29 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/dto/SopDetailCreateDTO.java
  6. 36 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/dto/SopDetailResponseDTO.java
  7. 30 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/dto/SopDetailUpdateDTO.java
  8. 36 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/dto/SopResponseDTO.java
  9. 23 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/dto/SopUpdateDTO.java
  10. 41 31
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/entity/MarketingCampaignEntity.java
  11. 0 9
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/mapper/SopDetailEntityMapper.java
  12. 12 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/mapper/SopDetailMapper.java
  13. 5 2
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/mapper/SopMapper.java
  14. 7 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/MarketingCampaignEntityService.java
  15. 0 7
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/SopDetailEntityService.java
  16. 10 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/SopDetailService.java
  17. 0 7
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/SopEntityService.java
  18. 43 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/SopService.java
  19. 80 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/impl/MarketingCampaignEntityServiceImpl.java
  20. 0 14
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/impl/SopDetailEntityServiceImpl.java
  21. 16 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/impl/SopDetailServiceImpl.java
  22. 0 14
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/impl/SopEntityServiceImpl.java
  23. 165 0
      java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/impl/SopServiceImpl.java

+ 56 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/controller/MarketingController.java

@@ -1,13 +1,69 @@
 package com.storlead.crm.marketing.controller;
 
+import com.storlead.crm.marketing.dto.MarketingCampaignDTO;
+import com.storlead.crm.marketing.service.MarketingCampaignEntityService;
+import com.storlead.framework.common.result.Result;
 import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
+
 @RestController
 @RequestMapping("/marketing")
 @Api(tags = "营销活动")
 public class MarketingController {
 
+    @Autowired
+    private MarketingCampaignEntityService marketingService;
+    @RequestMapping("/list")
+    @ApiOperation("营销活动列表")
+    public Result<Object> list(@RequestBody MarketingCampaignDTO marketingCampaignDTO) {
+
+        Result<Object> result = marketingService.getList(marketingCampaignDTO);
+        return Result.ok(result);
+    }
+
+    @PostMapping(value = "/add")
+    @ApiOperation(value = "营销活动添加", notes = "营销活动添加简报")
+    @Transactional(rollbackFor = Throwable.class)
+    public Result<?> add(@RequestBody MarketingCampaignDTO marketingCampaignDTO) {
+        Result<Object> result = marketingService.addMarket(marketingCampaignDTO);
+        return Result.ok(result);
+    }
+
+    @PostMapping(value = "/edit")
+    @ApiOperation(value = "营销活动修改", notes = "营销活动修改")
+    @Transactional(rollbackFor = Throwable.class)
+    public Result<?> edit(@RequestBody MarketingCampaignDTO marketingCampaignDTO) {
+        Result<Object> result = marketingService.editMarket(marketingCampaignDTO);
+        return Result.ok(result);
+    }
+
+    @PostMapping(value = "/delete")
+    @ApiOperation(value = "营销活动修改", notes = "营销活动修改")
+    @Transactional(rollbackFor = Throwable.class)
+    public Result<?> delete(@RequestBody MarketingCampaignDTO marketingCampaignDTO) {
+        boolean isOk = false;
+        Long id = marketingCampaignDTO.getId();
+        if (!ObjectUtils.isEmpty(id)) {
+            isOk = marketingService.removeById(id);
+        }
+        List<Long> idList = marketingCampaignDTO.getIdList();
+        if (!CollectionUtils.isEmpty(idList)){
+            isOk = marketingService.removeByIds(idList);
+        }
+        if (!isOk){
+            return Result.error("删除失败");
+        }
+        return Result.ok();
+    }
 
 }

+ 156 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/controller/SopController.java

@@ -0,0 +1,156 @@
+package com.storlead.crm.marketing.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.storlead.crm.marketing.dto.SopCreateDTO;
+import com.storlead.crm.marketing.dto.SopDetailCreateDTO;
+import com.storlead.crm.marketing.dto.SopDetailUpdateDTO;
+import com.storlead.crm.marketing.dto.SopResponseDTO;
+import com.storlead.crm.marketing.dto.SopUpdateDTO;
+import com.storlead.crm.marketing.service.SopService;
+import com.storlead.framework.common.result.Result;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.ObjectUtils;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * SOP管理 Controller
+ *
+ * @author Generated
+ */
+@Slf4j
+@RestController
+@RequestMapping("/api/sop")
+@Api(tags = "SOP管理接口")
+@Validated
+public class SopController {
+
+    @Resource
+    private SopService sopService;
+
+    /**
+     * 创建SOP(包含步骤明细)
+     *
+     * @param dto SOP创建请求
+     * @return SOP ID
+     */
+    @PostMapping
+    @ApiOperation(value = "创建SOP", notes = "创建SOP主表及步骤明细")
+    public Result<Object> createSop(@Valid @RequestBody SopCreateDTO dto) {
+        Result<Object> result = sopService.createSop(dto.getName(), dto.getDetails());
+        return result;
+    }
+
+    /**
+     * 根据ID查询SOP详情(包含步骤明细)
+     *
+     * @param id SOP ID
+     * @return SOP详情
+     */
+    @GetMapping("/{id}")
+    @ApiOperation(value = "查询SOP详情", notes = "根据ID查询SOP主表及步骤明细")
+    public Result<Object> getSopDetail(
+            @ApiParam(value = "SOP ID", required = true)
+            @PathVariable Long id) {
+        try {
+            SopResponseDTO detail = sopService.getSopDetail(id);
+            return Result.ok(detail);
+        } catch (Exception e) {
+            log.error("查询SOP详情失败, ID: {}", id, e);
+            return Result.error("查询失败: " );
+        }
+    }
+
+    /**
+     * 分页查询SOP列表
+     *
+     * @RequestBody SopResponseDTO dto
+     * @return SOP列表
+     */
+    @GetMapping
+    @ApiOperation(value = "分页查询SOP列表", notes = "支持按名称模糊查询")
+    public Result<Object> listSop(@RequestBody SopResponseDTO dto) {
+        try {
+            IPage<SopResponseDTO> page = sopService.listSopPage(dto);
+            return Result.ok(page);
+        } catch (Exception e) {
+            log.error("查询SOP列表失败", e);
+            return Result.error("查询失败");
+        }
+    }
+
+    /**
+     * 更新SOP(包含步骤明细)
+     *
+     * @param id  SOP ID
+     * @param dto SOP更新请求
+     * @return 更新结果
+     */
+    @PutMapping("/{id}")
+    @ApiOperation(value = "更新SOP", notes = "更新SOP主表及步骤明细(会删除旧明细,重新插入)")
+    public Result<Object> updateSop(
+            @ApiParam(value = "SOP ID", required = true)
+            @PathVariable Long id,
+            @Valid @RequestBody SopUpdateDTO dto) {
+        try {
+            sopService.updateSop(id, dto.getName(), dto.getDetails());
+            return Result.ok();
+        } catch (Exception e) {
+            log.error("更新SOP失败, ID: {}", id, e);
+            return Result.error("更新失败: " +e.getMessage());
+        }
+    }
+
+    /**
+     * 删除SOP(级联删除步骤明细)
+     *
+     * @param id SOP ID
+     * @return 删除结果
+     */
+    @DeleteMapping("/{id}")
+    @ApiOperation(value = "删除SOP", notes = "删除SOP主表及关联的步骤明细")
+    public Result<Object> deleteSop(
+            @ApiParam(value = "SOP ID", required = true)
+            @PathVariable Long id) {
+        try {
+            sopService.deleteSop(id);
+            return Result.ok();
+        } catch (Exception e) {
+            log.error("删除SOP失败, ID: {}", id, e);
+            return Result.error("删除失败: " +e.getMessage());
+        }
+    }
+
+    /**
+     * 批量删除SOP
+     *
+     * @param ids SOP ID列表
+     * @return 删除结果
+     */
+    @DeleteMapping("/batch")
+    @ApiOperation(value = "批量删除SOP", notes = "批量删除SOP主表及关联的步骤明细")
+    public Result<Object> batchDeleteSop(
+            @ApiParam(value = "SOP ID列表", required = true)
+            @RequestBody List<Long> ids) {
+        try {
+            for (Long id : ids) {
+                sopService.deleteSop(id);
+            }
+            return Result.ok();
+        } catch (Exception e) {
+            log.error("批量删除SOP失败, IDs: {}", ids, e);
+            return  Result.error("批量删除SOP失败: {}", e.getMessage());
+        }
+    }
+
+
+}

+ 25 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/dto/MarketingCampaignDTO.java

@@ -0,0 +1,25 @@
+package com.storlead.crm.marketing.dto;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.storlead.crm.marketing.entity.MarketingCampaignEntity;
+import com.storlead.framework.mybatis.entity.SysBaseField;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Data
+@TableName("marketing_campaign")
+public class MarketingCampaignDTO extends MarketingCampaignEntity {
+    @ApiModelProperty(value = "idList")
+    private List<Long> idList;
+
+    @ApiModelProperty(value = "关联客户id")
+    private List<Long> customerIdList;
+
+
+}

+ 25 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/dto/SopCreateDTO.java

@@ -0,0 +1,25 @@
+package com.storlead.crm.marketing.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import java.util.List;
+
+/**
+ * SOP创建DTO
+ */
+@Data
+@ApiModel(value = "SopCreateDTO", description = "SOP创建请求")
+public class SopCreateDTO {
+
+    @ApiModelProperty(value = "SOP名称", required = true)
+    @NotBlank(message = "SOP名称不能为空")
+    private String name;
+
+    @ApiModelProperty(value = "SOP步骤明细", required = true)
+    @NotEmpty(message = "SOP步骤不能为空")
+    private List<SopDetailCreateDTO> details;
+}

+ 29 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/dto/SopDetailCreateDTO.java

@@ -0,0 +1,29 @@
+package com.storlead.crm.marketing.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * SOP明细创建DTO
+ */
+@Data
+@ApiModel(value = "SopDetailCreateDTO", description = "SOP步骤明细创建请求")
+public class SopDetailCreateDTO implements Serializable {
+
+    @ApiModelProperty(value = "步骤序号", required = true)
+    @NotNull(message = "步骤序号不能为空")
+    private Integer step;
+
+    @ApiModelProperty(value = "步骤名称", required = true)
+    private String name;
+
+    @ApiModelProperty(value = "间隔天数")
+    private String days;
+
+    @ApiModelProperty(value = "触达渠道")
+    private String type;
+}

+ 36 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/dto/SopDetailResponseDTO.java

@@ -0,0 +1,36 @@
+package com.storlead.crm.marketing.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * SOP明细响应DTO
+ */
+@Data
+@ApiModel(value = "SopDetailResponseDTO", description = "SOP步骤明细响应")
+public class SopDetailResponseDTO {
+
+    @ApiModelProperty(value = "明细ID")
+    private Long id;
+
+    @ApiModelProperty(value = "SOP ID")
+    private Long sopId;
+
+    @ApiModelProperty(value = "步骤序号")
+    private Integer step;
+
+    @ApiModelProperty(value = "步骤名称")
+    private String name;
+
+    @ApiModelProperty(value = "间隔天数")
+    private String days;
+
+    @ApiModelProperty(value = "触达渠道")
+    private String type;
+
+    @ApiModelProperty(value = "创建时间")
+    private LocalDateTime createTime;
+}

+ 30 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/dto/SopDetailUpdateDTO.java

@@ -0,0 +1,30 @@
+package com.storlead.crm.marketing.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * SOP明细更新DTO
+ */
+@Data
+@ApiModel(value = "SopDetailUpdateDTO", description = "SOP步骤明细更新请求")
+public class SopDetailUpdateDTO implements Serializable {
+
+    @ApiModelProperty(value = "明细ID(更新时必填,新增时为空)")
+    private Long id;
+
+    @ApiModelProperty(value = "步骤序号")
+    private Integer step;
+
+    @ApiModelProperty(value = "步骤名称")
+    private String name;
+
+    @ApiModelProperty(value = "间隔天数")
+    private String days;
+
+    @ApiModelProperty(value = "触达渠道")
+    private String type;
+}

+ 36 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/dto/SopResponseDTO.java

@@ -0,0 +1,36 @@
+package com.storlead.crm.marketing.dto;
+
+import com.storlead.framework.common.dto.page.PageDTO;
+import com.storlead.framework.mybatis.page.Page;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * SOP响应DTO
+ */
+@Data
+@ApiModel(value = "SopResponseDTO", description = "SOP响应")
+public class SopResponseDTO extends PageDTO {
+
+    @ApiModelProperty(value = "SOP ID")
+    private Long id;
+
+    @ApiModelProperty(value = "SOP名称")
+    private String name;
+
+    @ApiModelProperty(value = "创建人")
+    private String createBy;
+
+    @ApiModelProperty(value = "创建时间")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "更新时间")
+    private LocalDateTime updateTime;
+
+    @ApiModelProperty(value = "SOP步骤明细")
+    private List<SopDetailResponseDTO> details;
+}

+ 23 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/dto/SopUpdateDTO.java

@@ -0,0 +1,23 @@
+package com.storlead.crm.marketing.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.util.List;
+
+/**
+ * SOP更新DTO
+ */
+@Data
+@ApiModel(value = "SopUpdateDTO", description = "SOP更新请求")
+public class SopUpdateDTO {
+
+    @ApiModelProperty(value = "SOP名称", required = true)
+    @NotBlank(message = "SOP名称不能为空")
+    private String name;
+
+    @ApiModelProperty(value = "SOP步骤明细")
+    private List<SopDetailUpdateDTO> details;
+}

+ 41 - 31
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/entity/MarketingCampaignEntity.java

@@ -1,12 +1,16 @@
 package com.storlead.crm.marketing.entity;
 
+import com.alibaba.fastjson.annotation.JSONField;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import com.storlead.framework.mybatis.entity.SysBaseField;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 
@@ -21,19 +25,25 @@ public class MarketingCampaignEntity extends SysBaseField {
     @TableField("name")
     private String name;
 
-    @ApiModelProperty(value = "活动类型")
+    @ApiModelProperty(value = "活动类型(1潜客开发、2客户培养、3客户唤醒、4产品推广、5节日营销、6展会跟进)")
     @TableField("type")
     private Integer type;
 
-    @ApiModelProperty(value = "优先级")
+    @ApiModelProperty(value = "优先级(1紧急、2高优先、3中等、4低优先)")
     @TableField("priority")
     private Integer priority;
 
     @ApiModelProperty(value = "开始日期")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+    @JSONField(format ="yyyy-MM-dd")
     @TableField("begin_data")
     private LocalDate beginData;
 
     @ApiModelProperty(value = "结束日期")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+    @JSONField(format ="yyyy-MM-dd")
     @TableField("end_date")
     private LocalDate endDate;
 
@@ -89,15 +99,15 @@ public class MarketingCampaignEntity extends SysBaseField {
     @TableField("email_subject")
     private String emailSubject;
 
-    @ApiModelProperty(value = "是否追踪邮件打开")
+    @ApiModelProperty(value = "是否追踪邮件打开(1是0否)")
     @TableField("track_config_open")
     private Integer trackConfigOpen;
 
-    @ApiModelProperty(value = "是否追踪链接点击")
+    @ApiModelProperty(value = "是否追踪链接点击(1是0否)")
     @TableField("track_config_click")
     private Integer trackConfigClick;
 
-    @ApiModelProperty(value = "是否追踪回复")
+    @ApiModelProperty(value = "是否追踪回复(1是0否)")
     @TableField("track_config_reply")
     private Integer trackConfigReply;
 
@@ -105,41 +115,41 @@ public class MarketingCampaignEntity extends SysBaseField {
     @TableField("sop_id")
     private Integer sopId;
 
-    @ApiModelProperty(value = "未打开邮件跟进规则")
-    @TableField("follow-up_rules_not_opened")
-    private String followUpRulesNotOpened;
+    @ApiModelProperty(value = "未打开邮件跟进规则(1是0否)")
+    @TableField("follow_up_rules_not_opened")
+    private Integer followUpRulesNotOpened;
 
     @ApiModelProperty(value = "未打开邮件跟进天数")
-    @TableField("follow-up_rules_not_opened_days")
+    @TableField("follow_up_rules_not_opened_days")
     private String followUpRulesNotOpenedDays;
 
-    @ApiModelProperty(value = "未回复邮件跟进规则")
-    @TableField("follow-up_rules_not_replied")
-    private String followUpRulesNotReplied;
+    @ApiModelProperty(value = "未回复邮件跟进规则(1是0否)")
+    @TableField("follow_up_rules_not_replied")
+    private Integer followUpRulesNotReplied;
 
     @ApiModelProperty(value = "未回复邮件跟进天数")
-    @TableField("follow-up_rules_not_replied_days")
+    @TableField("follow_up_rules_not_replied_days")
     private String followUpRulesNotRepliedDays;
 
-    @ApiModelProperty(value = "未点击链接跟进规则")
-    @TableField("follow-up_rules_link_not_clicked")
-    private String followUpRulesLinkNotClicked;
+    @ApiModelProperty(value = "未点击链接跟进规则(1是0否)")
+    @TableField("follow_up_rules_link_not_clicked")
+    private Integer followUpRulesLinkNotClicked;
 
     @ApiModelProperty(value = "未点击链接跟进天数")
-    @TableField("follow-up_rules_link_not_clicked_days")
+    @TableField("follow_up_rules_link_not_clicked_days")
     private String followUpRulesLinkNotClickedDays;
 
-    @ApiModelProperty(value = "客户回复后自动停止")
-    @TableField("follow-up_rules_replied")
-    private String followUpRulesReplied;
+    @ApiModelProperty(value = "客户回复后自动停止(1是0否)")
+    @TableField("follow_up_rules_replied")
+    private Integer followUpRulesReplied;
 
-    @ApiModelProperty(value = "客户预约后停止")
-    @TableField("follow-up_rules_appointment_booked")
-    private String followUpRulesAppointmentBooked;
+    @ApiModelProperty(value = "客户预约后停止(1是0否)")
+    @TableField("follow_up_rules_appointment_booked")
+    private Integer followUpRulesAppointmentBooked;
 
-    @ApiModelProperty(value = "A/B测试")
+    @ApiModelProperty(value = "A/B测试(1是0否)")
     @TableField("a_b_testing")
-    private String abTesting;
+    private Integer aBTesting;
 
     @ApiModelProperty(value = "智能调度类型")
     @TableField("smart_scheduling_type")
@@ -154,16 +164,16 @@ public class MarketingCampaignEntity extends SysBaseField {
     private String smartSchedulingStartTime;
 
     @ApiModelProperty(value = "是否已确认内容合规")
-    @TableField("is_content_compliant")
-    private Integer isContentCompliant;
+    @TableField("has_content_compliant")
+    private Integer hasContentCompliant;
 
     @ApiModelProperty(value = "是否已确认发送时间合理")
-    @TableField("is_schedule_approved")
-    private Integer isScheduleApproved;
+    @TableField("has_schedule_approved")
+    private Integer hasScheduleApproved;
 
     @ApiModelProperty(value = "是否符合GDPR")
-    @TableField("is_gdpr_compliant")
-    private Integer isGdprCompliant;
+    @TableField("has_gdpr_compliant")
+    private Integer hasGdprCompliant;
 
     @ApiModelProperty(value = "是否包含退订链接")
     @TableField("has_unsubscribe_link")

+ 0 - 9
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/mapper/SopDetailEntityMapper.java

@@ -1,9 +0,0 @@
-package com.storlead.crm.marketing.mapper;
-
-import com.storlead.crm.marketing.entity.SopDetailEntity;
-import com.storlead.framework.mybatis.mapper.MyBaseMapper;
-import org.apache.ibatis.annotations.Mapper;
-
-@Mapper
-public interface SopDetailEntityMapper extends MyBaseMapper<SopDetailEntity> {
-}

+ 12 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/mapper/SopDetailMapper.java

@@ -0,0 +1,12 @@
+package com.storlead.crm.marketing.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.storlead.crm.marketing.entity.SopDetailEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * SOP明细 Mapper接口
+ */
+@Mapper
+public interface SopDetailMapper extends BaseMapper<SopDetailEntity> {
+}

+ 5 - 2
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/mapper/SopEntityMapper.java → java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/mapper/SopMapper.java

@@ -1,9 +1,12 @@
 package com.storlead.crm.marketing.mapper;
 
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.storlead.crm.marketing.entity.SopEntity;
-import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 
+/**
+ * SOP Mapper接口
+ */
 @Mapper
-public interface SopEntityMapper extends MyBaseMapper<SopEntity> {
+public interface SopMapper extends BaseMapper<SopEntity> {
 }

+ 7 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/MarketingCampaignEntityService.java

@@ -1,8 +1,15 @@
 package com.storlead.crm.marketing.service;
 
 
+import com.storlead.crm.marketing.dto.MarketingCampaignDTO;
 import com.storlead.crm.marketing.entity.MarketingCampaignEntity;
+import com.storlead.framework.common.result.Result;
 import com.storlead.framework.mybatis.service.MyBaseService;
 
 public interface MarketingCampaignEntityService extends MyBaseService<MarketingCampaignEntity> {
+    Result<Object> getList(MarketingCampaignDTO marketingCampaignDTO);
+
+    Result<Object> addMarket(MarketingCampaignDTO marketingCampaignDTO);
+
+    Result<Object> editMarket(MarketingCampaignDTO marketingCampaignDTO);
 }

+ 0 - 7
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/SopDetailEntityService.java

@@ -1,7 +0,0 @@
-package com.storlead.crm.marketing.service;
-
-import com.storlead.crm.marketing.entity.SopDetailEntity;
-import com.storlead.framework.mybatis.service.MyBaseService;
-
-public interface SopDetailEntityService extends MyBaseService<SopDetailEntity> {
-}

+ 10 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/SopDetailService.java

@@ -0,0 +1,10 @@
+package com.storlead.crm.marketing.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.storlead.crm.marketing.entity.SopDetailEntity;
+
+/**
+ * SOP明细 Service接口
+ */
+public interface SopDetailService extends IService<SopDetailEntity> {
+}

+ 0 - 7
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/SopEntityService.java

@@ -1,7 +0,0 @@
-package com.storlead.crm.marketing.service;
-
-import com.storlead.crm.marketing.entity.SopEntity;
-import com.storlead.framework.mybatis.service.MyBaseService;
-
-public interface SopEntityService extends MyBaseService<SopEntity> {
-}

+ 43 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/SopService.java

@@ -0,0 +1,43 @@
+package com.storlead.crm.marketing.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.storlead.crm.marketing.dto.SopDetailCreateDTO;
+import com.storlead.crm.marketing.dto.SopDetailUpdateDTO;
+import com.storlead.crm.marketing.dto.SopResponseDTO;
+import com.storlead.crm.marketing.entity.SopEntity;
+import com.storlead.framework.common.result.Result;
+
+import java.util.List;
+
+/**
+ * SOP Service接口
+ */
+public interface SopService extends IService<SopEntity> {
+
+    /**
+     * 创建SOP(包含明细)
+     */
+    Result<Object> createSop(String name, List<SopDetailCreateDTO> details);
+
+    /**
+     * 更新SOP(包含明细)
+     */
+    void updateSop(Long id, String name, List<SopDetailUpdateDTO> details);
+
+    /**
+     * 删除SOP(级联删除明细)
+     */
+    void deleteSop(Long id);
+
+    /**
+     * 获取SOP详情(包含明细)
+     */
+    SopResponseDTO getSopDetail(Long id);
+
+    /**
+     * 分页查询SOP列表
+     */
+    IPage<SopResponseDTO> listSopPage(
+            SopResponseDTO dto);
+}

+ 80 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/impl/MarketingCampaignEntityServiceImpl.java

@@ -1,14 +1,94 @@
 package com.storlead.crm.marketing.service.impl;
 
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.storlead.crm.marketing.dto.MarketingCampaignDTO;
+import com.storlead.crm.marketing.entity.CustomerBaseEntity;
 import com.storlead.crm.marketing.entity.MarketingCampaignEntity;
 import com.storlead.crm.marketing.mapper.MarketingCampaignEntityMapper;
+import com.storlead.crm.marketing.service.CustomerBaseEntityService;
 import com.storlead.crm.marketing.service.MarketingCampaignEntityService;
+import com.storlead.framework.common.constant.CommonConstant;
+import com.storlead.framework.common.result.Result;
 import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
 
 @Service
 public class MarketingCampaignEntityServiceImpl
         extends MyBaseServiceImpl<MarketingCampaignEntityMapper, MarketingCampaignEntity>
         implements MarketingCampaignEntityService {
+
+    @Resource
+    private CustomerBaseEntityService customerBaseEntityService;
+    @Override
+    public Result<Object> getList(MarketingCampaignDTO marketingCampaignDTO) {
+        LambdaQueryWrapper<MarketingCampaignEntity> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(MarketingCampaignEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
+        List<MarketingCampaignEntity> list = this.list(queryWrapper);
+
+        return Result.ok(list);
+    }
+
+    @Override
+    public Result<Object> addMarket(MarketingCampaignDTO marketingCampaignDTO) {
+        MarketingCampaignEntity marketingCampaignEntity = new MarketingCampaignEntity();
+        BeanUtils.copyProperties(marketingCampaignDTO, marketingCampaignEntity);
+        boolean isOk = this.save(marketingCampaignEntity);
+        if (!isOk) {
+
+            return Result.error("添加失败");
+        }
+        //添加关联客户
+        List<Long> customerIdList = marketingCampaignDTO.getCustomerIdList();
+        if (!CollectionUtils.isEmpty(customerIdList)) {
+            List<CustomerBaseEntity> customerBaseEntityList = new ArrayList<>();
+            for (Long customerId : customerIdList) {
+                CustomerBaseEntity customerBaseEntity = new CustomerBaseEntity();
+                customerBaseEntity.setCustomerId(customerId);
+                customerBaseEntity.setMarketingCampaignId(marketingCampaignEntity.getId());
+                customerBaseEntityList.add(customerBaseEntity);
+            }
+            boolean saveOk =customerBaseEntityService.saveBatch(customerBaseEntityList);
+            if (!saveOk){
+                return Result.error("添加失败");
+            }
+        }
+        return Result.ok();
+    }
+
+    @Override
+    public Result<Object> editMarket(MarketingCampaignDTO marketingCampaignDTO) {
+        MarketingCampaignEntity marketingCampaignEntity = new MarketingCampaignEntity();
+        BeanUtils.copyProperties(marketingCampaignDTO, marketingCampaignEntity);
+        boolean isOk = this.updateById(marketingCampaignEntity);
+        if (!isOk) {
+            return Result.error("修改失败");
+        }
+        //添加关联客户
+        List<Long> customerIdList = marketingCampaignDTO.getCustomerIdList();
+        LambdaUpdateWrapper<CustomerBaseEntity> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.eq(CustomerBaseEntity::getMarketingCampaignId, marketingCampaignEntity.getId());
+        customerBaseEntityService.remove(updateWrapper);
+        if (!CollectionUtils.isEmpty(customerIdList)) {
+            List<CustomerBaseEntity> customerBaseEntityList = new ArrayList<>();
+            for (Long customerId : customerIdList) {
+                CustomerBaseEntity customerBaseEntity = new CustomerBaseEntity();
+                customerBaseEntity.setCustomerId(customerId);
+                customerBaseEntity.setMarketingCampaignId(marketingCampaignEntity.getId());
+                customerBaseEntityList.add(customerBaseEntity);
+            }
+            boolean saveOk =customerBaseEntityService.saveBatch(customerBaseEntityList);
+            if (!saveOk){
+                return Result.error("修改失败");
+            }
+        }
+        return Result.ok();
+    }
 }

+ 0 - 14
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/impl/SopDetailEntityServiceImpl.java

@@ -1,14 +0,0 @@
-package com.storlead.crm.marketing.service.impl;
-
-
-import com.storlead.crm.marketing.entity.SopDetailEntity;
-import com.storlead.crm.marketing.mapper.SopDetailEntityMapper;
-import com.storlead.crm.marketing.service.SopDetailEntityService;
-import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
-import org.springframework.stereotype.Service;
-
-@Service
-public class SopDetailEntityServiceImpl
-        extends MyBaseServiceImpl<SopDetailEntityMapper, SopDetailEntity>
-        implements SopDetailEntityService {
-}

+ 16 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/impl/SopDetailServiceImpl.java

@@ -0,0 +1,16 @@
+package com.storlead.crm.marketing.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.storlead.crm.marketing.entity.SopDetailEntity;
+import com.storlead.crm.marketing.mapper.SopDetailMapper;
+import com.storlead.crm.marketing.service.SopDetailService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * SOP明细 Service实现类
+ */
+@Slf4j
+@Service
+public class SopDetailServiceImpl extends ServiceImpl<SopDetailMapper, SopDetailEntity> implements SopDetailService {
+}

+ 0 - 14
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/impl/SopEntityServiceImpl.java

@@ -1,14 +0,0 @@
-package com.storlead.crm.marketing.service.impl;
-
-
-import com.storlead.crm.marketing.entity.SopEntity;
-import com.storlead.crm.marketing.mapper.SopEntityMapper;
-import com.storlead.crm.marketing.service.SopEntityService;
-import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
-import org.springframework.stereotype.Service;
-
-@Service
-public class SopEntityServiceImpl
-        extends MyBaseServiceImpl<SopEntityMapper, SopEntity>
-        implements SopEntityService {
-}

+ 165 - 0
java/storlead-sasa/storlead-trade/storlead-marketing/src/main/java/com/storlead/crm/marketing/service/impl/SopServiceImpl.java

@@ -0,0 +1,165 @@
+package com.storlead.crm.marketing.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.storlead.crm.marketing.dto.SopCreateDTO;
+import com.storlead.crm.marketing.dto.SopDetailCreateDTO;
+import com.storlead.crm.marketing.dto.SopDetailResponseDTO;
+import com.storlead.crm.marketing.dto.SopDetailUpdateDTO;
+import com.storlead.crm.marketing.dto.SopResponseDTO;
+import com.storlead.crm.marketing.dto.SopUpdateDTO;
+import com.storlead.crm.marketing.entity.SopDetailEntity;
+import com.storlead.crm.marketing.entity.SopEntity;
+import com.storlead.crm.marketing.mapper.SopMapper;
+import com.storlead.crm.marketing.service.SopDetailService;
+import com.storlead.crm.marketing.service.SopService;
+import com.storlead.framework.common.result.Result;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * SOP Service实现类
+ */
+@Slf4j
+@Service
+public class SopServiceImpl extends ServiceImpl<SopMapper, SopEntity> implements SopService {
+
+    @Resource
+    private SopDetailService sopDetailService;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Result<Object> createSop(String name, List<SopDetailCreateDTO> details) {
+        boolean isOk = false;
+        // 1. 创建SOP主表
+        SopEntity sop = new SopEntity();
+        sop.setName(name);
+        isOk = save(sop);
+
+        // 2. 批量创建SOP明细
+        if (details != null && !details.isEmpty()) {
+            List<SopDetailEntity> detailEntities = details.stream().map(dto -> {
+                SopDetailEntity detail = new SopDetailEntity();
+                BeanUtils.copyProperties(dto, detail);
+                detail.setSopId(sop.getId());
+                return detail;
+            }).collect(Collectors.toList());
+
+            isOk = sopDetailService.saveBatch(detailEntities);
+        }
+
+        if(!isOk){
+            return Result.error("创建失败");
+        }
+        return Result.ok();
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateSop(Long id, String name, List<SopDetailUpdateDTO> details) {
+        // 1. 更新SOP主表
+        SopEntity sop = getById(id);
+        if (sop == null) {
+            throw new RuntimeException("SOP不存在,ID: " + id);
+        }
+        sop.setName(name);
+        updateById(sop);
+
+        // 2. 删除旧的明细,重新插入新的明细
+        LambdaQueryWrapper<SopDetailEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SopDetailEntity::getSopId, id);
+        sopDetailService.remove(wrapper);
+
+        // 3. 批量创建新的明细
+        if (details != null && !details.isEmpty()) {
+            List<SopDetailEntity> detailEntities = details.stream().map(dto -> {
+                SopDetailEntity detail = new SopDetailEntity();
+                BeanUtils.copyProperties(dto, detail);
+                detail.setSopId(id);
+                return detail;
+            }).collect(Collectors.toList());
+
+            sopDetailService.saveBatch(detailEntities);
+        }
+
+        log.info("更新SOP成功,ID: {}", id);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteSop(Long id) {
+        // 1. 删除SOP明细
+        LambdaQueryWrapper<SopDetailEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SopDetailEntity::getSopId, id);
+        sopDetailService.remove(wrapper);
+
+        // 2. 删除SOP主表
+        removeById(id);
+
+        log.info("删除SOP成功,ID: {}", id);
+    }
+
+    @Override
+    public SopResponseDTO getSopDetail(Long id) {
+        SopResponseDTO response = new SopResponseDTO();
+
+        // 1. 查询SOP主表
+        SopEntity sop = getById(id);
+        if (sop == null) {
+            throw new RuntimeException("SOP不存在,ID: " + id);
+        }
+        BeanUtils.copyProperties(sop, response);
+
+        // 2. 查询SOP明细
+        LambdaQueryWrapper<SopDetailEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SopDetailEntity::getSopId, id);
+        wrapper.orderByAsc(SopDetailEntity::getStep);
+        List<SopDetailEntity> details = sopDetailService.list(wrapper);
+
+        // 3. 转换明细
+        List<SopDetailResponseDTO> detailResponses = details.stream().map(detail -> {
+            SopDetailResponseDTO dto = new SopDetailResponseDTO();
+            BeanUtils.copyProperties(detail, dto);
+            return dto;
+        }).collect(Collectors.toList());
+
+        response.setDetails(detailResponses);
+
+        return response;
+    }
+
+    @Override
+    public IPage<SopResponseDTO> listSopPage(SopResponseDTO dto) {
+        Integer pageIndex = dto.getPageIndex();
+        Integer pageSize = dto.getPageSize();
+        String name = dto.getName();
+        // 1. 分页查询SOP主表
+        Page<SopEntity> page = new Page<>(pageIndex, pageSize);
+        LambdaQueryWrapper<SopEntity> wrapper = new LambdaQueryWrapper<>();
+        if (name != null && !name.trim().isEmpty()) {
+            wrapper.like(SopEntity::getName, name);
+        }
+        wrapper.orderByDesc(SopEntity::getCreateTime);
+        IPage<SopEntity> sopPage = page(page, wrapper);
+
+        // 2. 转换为响应DTO
+        IPage<SopResponseDTO> responsePage = new Page<>(pageIndex, pageSize, sopPage.getTotal());
+        List<SopResponseDTO> records = sopPage.getRecords().stream().map(sop -> {
+            SopResponseDTO sopResponseDTO = new SopResponseDTO();
+            BeanUtils.copyProperties(sop, sopResponseDTO);
+            return sopResponseDTO;
+        }).collect(Collectors.toList());
+        responsePage.setRecords(records);
+
+        return responsePage;
+    }
+}