Browse Source

增加销售预测主表关联及相关接口

bai 4 months ago
parent
commit
e3e28fbc11
20 changed files with 1070 additions and 10 deletions
  1. 4 0
      blade-service-api/blade-factory-api/src/main/java/org/springblade/factory/entity/PcBladeClaim.java
  2. 69 0
      blade-service-api/blade-factory-api/src/main/java/org/springblade/factory/entity/PcBladeSalesForecastMain.java
  3. 4 0
      blade-service-api/blade-factory-api/src/main/java/org/springblade/factory/entity/PcBladeSalesForecastSummary.java
  4. 4 0
      blade-service-api/blade-factory-api/src/main/java/org/springblade/factory/entity/PcBladeSalesLead.java
  5. 26 0
      blade-service-api/blade-u9cloud-api/src/main/java/org/springblade/u9cloud/feign/IZcrmViewCustomerSel.java
  6. 173 9
      blade-service/blade-factory/src/main/java/org/springblade/factory/api/controller/SalesForecastSummaryController.java
  7. 98 0
      blade-service/blade-factory/src/main/java/org/springblade/factory/controller/PcBladeSalesForecastMainController.java
  8. 16 0
      blade-service/blade-factory/src/main/java/org/springblade/factory/mapper/PcBladeSalesForecastMainMapper.java
  9. 5 0
      blade-service/blade-factory/src/main/java/org/springblade/factory/mapper/xml/PcBladeSalesForecastMainMapper.xml
  10. 80 0
      blade-service/blade-factory/src/main/java/org/springblade/factory/service/PcBladeSalesForecastMainService.java
  11. 2 0
      blade-service/blade-factory/src/main/java/org/springblade/factory/service/PcBladeSalesForecastSummaryService.java
  12. 310 0
      blade-service/blade-factory/src/main/java/org/springblade/factory/service/impl/PcBladeSalesForecastMainServiceImpl.java
  13. 100 0
      blade-service/blade-factory/src/main/java/org/springblade/factory/service/impl/PcBladeSalesForecastSummaryServiceImpl.java
  14. 19 0
      blade-service/blade-u9cloud/src/main/java/org/springblade/u9cloud/Test/TestU9cloudController.java
  15. 4 1
      blade-service/blade-u9cloud/src/main/java/org/springblade/u9cloud/U9cloudApplication.java
  16. 23 0
      blade-service/blade-u9cloud/src/main/java/org/springblade/u9cloud/config/FeignConfig.java
  17. 94 0
      blade-service/blade-u9cloud/src/main/java/org/springblade/u9cloud/controller/CommonController.java
  18. 15 0
      blade-service/blade-u9cloud/src/main/java/org/springblade/u9cloud/controller/ZcrmViewCustomerSelController.java
  19. 7 0
      blade-service/blade-u9cloud/src/main/java/org/springblade/u9cloud/service/ZcrmViewCustomerSelService.java
  20. 17 0
      blade-service/blade-u9cloud/src/main/java/org/springblade/u9cloud/service/impl/ZcrmViewCustomerSelServiceImpl.java

+ 4 - 0
blade-service-api/blade-factory-api/src/main/java/org/springblade/factory/entity/PcBladeClaim.java

@@ -88,4 +88,8 @@ public class PcBladeClaim extends BaseEntity {
 	@TableField("submit_time")
 	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
 	private LocalDateTime submitTime;
+
+	/** 版本 */
+	@TableField("version")
+	private String version;
 }

+ 69 - 0
blade-service-api/blade-factory-api/src/main/java/org/springblade/factory/entity/PcBladeSalesForecastMain.java

@@ -0,0 +1,69 @@
+package org.springblade.factory.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.mp.base.BaseEntity;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * <p>
+ * 销售预测主表
+ * </p>
+ *
+ * @author yourname
+ * @since 2025-09-10
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("pc_blade_sales_forecast_main")
+public class PcBladeSalesForecastMain extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@ApiModelProperty(value = "年份")
+	@TableField("year")
+	private Integer year;
+
+	@ApiModelProperty(value = "月份")
+	@TableField("month")
+	private Integer month;
+
+	@ApiModelProperty(value = "经销商ID(来源:zcrm_view_customer_sel.Customer_ID)")
+	@TableField("CUSTOMER_ID")
+	private Long customerId;
+
+	@ApiModelProperty(value = "经销商编码")
+	@TableField("CUSTOMER_CODE")
+	private String customerCode;
+
+	@ApiModelProperty(value = "经销商名称")
+	@TableField("CUSTOMER_NAME")
+	private String customerName;
+
+	@ApiModelProperty(value = "审批状态 0未审批 1已通过 2已拒绝")
+	@TableField("approval_status")
+	private Integer approvalStatus;
+
+	@ApiModelProperty(value = "审批人ID")
+	@TableField("approved_by")
+	private Long approvedBy;
+
+	@ApiModelProperty(value = "审批人姓名")
+	@TableField("approved_name")
+	private String approvedName;
+
+	@ApiModelProperty(value = "审批时间")
+	@TableField("approved_time")
+	private LocalDateTime approvedTime;
+
+	@TableField(exist = false)
+	private List<PcBladeSalesForecastSummary> PcBladeSalesForecastSummaryList;
+
+
+}
+

+ 4 - 0
blade-service-api/blade-factory-api/src/main/java/org/springblade/factory/entity/PcBladeSalesForecastSummary.java

@@ -13,6 +13,10 @@ import java.time.LocalDateTime;
 public class PcBladeSalesForecastSummary extends BaseEntity {
 	private static final long serialVersionUID = 1L;
 
+	/** 关联预测汇总主表ID */
+	@TableField("forecast_main_id")
+	private Long forecastMainId;
+
 	/** 年份 */
 	@TableField("year")
 	private Integer year;

+ 4 - 0
blade-service-api/blade-factory-api/src/main/java/org/springblade/factory/entity/PcBladeSalesLead.java

@@ -65,6 +65,10 @@ public class PcBladeSalesLead extends BaseEntity {
 	@TableField("close_reason")
 	private String closeReason;
 
+	/** 版本 */
+	@TableField("version")
+	private String version;
+
 	/**
 	 * 预测明细列表 - 非数据库字段
 	 * 添加exist = false表示该字段不对应数据库表中的任何列

+ 26 - 0
blade-service-api/blade-u9cloud-api/src/main/java/org/springblade/u9cloud/feign/IZcrmViewCustomerSel.java

@@ -0,0 +1,26 @@
+package org.springblade.u9cloud.feign;
+
+
+import org.springblade.core.tool.api.R;
+import org.springblade.u9cloud.entity.ZcrmViewCustomerSel;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+/**
+ * 客户档案表 Feign接口类
+ *
+ * @author Chill
+ */
+@FeignClient(
+	value = "blade-u9cloud"
+)
+public interface IZcrmViewCustomerSel {
+	/**
+	 * 调用服务提供者的新增接口
+	 * 注意:路径需要与服务提供者的完整路径一致
+	 * 服务提供者的完整路径 = Controller的@RequestMapping + 方法的@PostMapping
+	 */
+	@PostMapping("/api/viewCustomerSel/TestZcrmViewCustomerSelAdd") // 这里需要包含Controller类上的路径前缀
+	R<String> u9cloudAdd(@RequestBody ZcrmViewCustomerSel zcrmViewCustomerSel);
+}

+ 173 - 9
blade-service/blade-factory/src/main/java/org/springblade/factory/api/controller/SalesForecastSummaryController.java

@@ -1,6 +1,7 @@
 package org.springblade.factory.api.controller;
 
 
+import com.alibaba.excel.util.CollectionUtils;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
@@ -8,19 +9,14 @@ import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
 import org.springblade.core.secure.BladeUser;
 import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.tool.api.R;
-import org.springblade.factory.entity.PcBladeSalesForecastSummary;
-import org.springblade.factory.entity.PjpfBrandDesc;
-import org.springblade.factory.entity.PjpfStockDesc;
-import org.springblade.factory.entity.ViewCustomerSel;
-import org.springblade.factory.service.PcBladeSalesForecastSummaryService;
-import org.springblade.factory.service.PjpfBrandDescService;
-import org.springblade.factory.service.PjpfStockDescService;
-import org.springblade.factory.service.ZcrmViewCustomerSelService;
+import org.springblade.factory.entity.*;
+import org.springblade.factory.service.*;
 import org.springblade.u9cloud.entity.ZcrmViewCustomerSel;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
@@ -43,6 +39,7 @@ import java.util.Objects;
 @RestController
 @RequestMapping("/api/factory/salesForecastSummary")
 @AllArgsConstructor
+@Slf4j
 public class SalesForecastSummaryController {
 
 	/* ========== 经销商提报 ========== */
@@ -50,12 +47,173 @@ public class SalesForecastSummaryController {
 
 	private final ZcrmViewCustomerSelService customerSelService;
 
+	private final PcBladeSalesForecastMainService salesForecastMainService;
+
+
+	/**
+	 * 根据ID查询销售预测主表
+	 */
+	@GetMapping("/main-detail")
+	@ApiOperation(value = "查询销售预测详情", notes = "根据ID查询销售预测主表及关联明细")
+	public R<PcBladeSalesForecastMain> getDetail(
+		@ApiParam(value = "主表ID", required = true) @RequestParam Long id) {
+		if (id == null) {
+			return R.fail("ID不能为空");
+		}
+		PcBladeSalesForecastMain main = salesForecastMainService.selectPcBladeSalesForecastMainById(id);
+		return main != null ? R.data(main) : R.fail("数据不存在");
+	}
+
+	/**
+	 * 销售预测汇总列表 --主表接口
+	 */
+	@GetMapping("/main-list")
+	@ApiOperation(value = "销售预测汇总主列表", notes = "支持多条件筛选和分页,自动过滤当前登录用户数据")
+	public R<IPage<PcBladeSalesForecastMain>> mainList(
+		@ApiIgnore @RequestParam Map<String, Object> params,
+		Query query,
+		PcBladeSalesForecastMain pcBladeSalesForecastMain,
+		@RequestParam(required = false) @ApiParam("开始日期(格式:yyyy-MM)") String startMonth,
+		@RequestParam(required = false) @ApiParam("结束日期(格式:yyyy-MM)") String endMonth) {
+		// 1. 获取当前登录用户ID,设置数据权限
+		Long customerId = AuthUtil.getUserId();
+		params.put("customerId", customerId);
+
+		// 2. 构建基础查询条件
+		QueryWrapper<PcBladeSalesForecastMain> queryWrapper = Condition.getQueryWrapper(params, PcBladeSalesForecastMain.class);
+
+		// 3. 处理年月区间查询
+		try {
+			if (startMonth != null && !startMonth.isEmpty()) {
+				String[] startParts = startMonth.split("-");
+				queryWrapper.ge("year", Integer.parseInt(startParts[0]));
+				if (startParts.length > 1) {
+					queryWrapper.ge("month", Integer.parseInt(startParts[1]));
+				}
+			}
+
+			if (endMonth != null && !endMonth.isEmpty()) {
+				String[] endParts = endMonth.split("-");
+				queryWrapper.le("year", Integer.parseInt(endParts[0]));
+				if (endParts.length > 1) {
+					queryWrapper.le("month", Integer.parseInt(endParts[1]));
+				}
+			}
+		} catch (Exception e) {
+			return R.fail("日期格式错误,请使用yyyy-MM格式");
+		}
+
+		// 4. 设置排序方式
+		queryWrapper.orderByDesc("year", "month", "create_time");
+
+		// 5. 执行分页查询
+		IPage<PcBladeSalesForecastMain> pages = salesForecastMainService.pagePro(
+			Condition.getPage(query),
+			queryWrapper
+		);
+
+		// 6. 返回结果
+		return R.data(pages);
+	}
+
+	/**
+	 * 销售预测汇总列表 --添加接口
+	 */
+	@PostMapping("/main-add")
+	@ApiOperation(value = "销售预测汇总添加", notes = "添加销售预测主表及明细数据")
+	public R<String> mainAdd(@RequestBody PcBladeSalesForecastMain pcBladeSalesForecastMain) {
+		try {
+			// 验证参数
+			if (pcBladeSalesForecastMain == null) {
+				return R.fail("提交数据不能为空");
+			}
+
+			// 验证必要字段
+			if (pcBladeSalesForecastMain.getYear() == null || pcBladeSalesForecastMain.getMonth() == null) {
+				return R.fail("年份和月份为必填项");
+			}
+
+			// 调用Service层批量添加方法
+			boolean success = salesForecastMainService.batchAdd(pcBladeSalesForecastMain);
+
+			if (success) {
+				log.info("销售预测数据添加成功,主表ID: {}", pcBladeSalesForecastMain.getId());
+				return R.success("添加成功");
+			} else {
+				log.error("销售预测数据添加失败");
+				return R.fail("添加失败,请稍后重试");
+			}
+		} catch (Exception e) {
+			log.error("销售预测添加接口发生异常", e);
+			return R.fail("系统异常,请联系管理员");
+		}
+	}
+
+	/**
+	 * 销售预测汇总列表 --修改接口
+	 */
+	@PutMapping("/main-update")
+	@ApiOperation(value = "销售预测修改", notes = "修改销售预测主表及明细数据")
+	public R<String> mainUpdate(@RequestBody PcBladeSalesForecastMain pcBladeSalesForecastMain) {
+		try {
+			// 验证参数
+			if (pcBladeSalesForecastMain == null || pcBladeSalesForecastMain.getId() == null) {
+				return R.fail("主表ID不能为空");
+			}
+
+			// 调用Service层批量修改方法
+			boolean success = salesForecastMainService.batchUpdate(pcBladeSalesForecastMain);
+
+			if (success) {
+				log.info("销售预测数据修改成功,主表ID: {}", pcBladeSalesForecastMain.getId());
+				return R.success("修改成功");
+			} else {
+				log.error("销售预测数据修改失败,主表ID: {}", pcBladeSalesForecastMain.getId());
+				return R.fail("修改失败,请稍后重试");
+			}
+		} catch (Exception e) {
+			log.error("销售预测修改接口发生异常", e);
+			return R.fail("系统异常,请联系管理员");
+		}
+	}
+
+	/**
+	 * 销售预测汇总列表 --删除接口
+	 */
+	@DeleteMapping("/main-delete")
+	@ApiOperation(value = "销售预测删除", notes = "删除销售预测主表及明细数据")
+	public R<String> mainDelete(@RequestBody PcBladeSalesForecastMain pcBladeSalesForecastMain) {
+		try {
+			// 验证参数
+			if (pcBladeSalesForecastMain == null || pcBladeSalesForecastMain.getId() == null) {
+				return R.fail("主表ID不能为空");
+			}
+
+			// 调用Service层批量删除方法
+			boolean success = salesForecastMainService.batchDelete(pcBladeSalesForecastMain);
+
+			if (success) {
+				log.info("销售预测数据删除成功,主表ID: {}", pcBladeSalesForecastMain.getId());
+				return R.success("删除成功");
+			} else {
+				log.error("销售预测数据删除失败,主表ID: {}", pcBladeSalesForecastMain.getId());
+				return R.fail("删除失败,请稍后重试");
+			}
+		} catch (Exception e) {
+			log.error("销售预测删除接口发生异常", e);
+			return R.fail("系统异常,请联系管理员");
+		}
+	}
+
+
+
+
 
 	/**
 	 * 销售预测汇总列表
 	 */
 	@GetMapping("/list")
-	@ApiOperation(value = "销售预测汇总列表", notes = "支持多条件筛选和分页,自动过滤当前登录用户数据")
+	@ApiOperation(value = "销售预测汇总明细列表", notes = "支持多条件筛选和分页,自动过滤当前登录用户数据")
 	public R<IPage<PcBladeSalesForecastSummary>> list(
 		@ApiIgnore @RequestParam Map<String, Object> params,
 		Query query,
@@ -235,6 +393,11 @@ public class SalesForecastSummaryController {
 		return forecastService.batchSaveOrUpdateForecasts(forecasts);
 	}
 
+
+
+
+
+
 	/**
 	 * 根据登录的ID,找到最新的一条预测提报信息
 	 */
@@ -361,4 +524,5 @@ public class SalesForecastSummaryController {
 		PjpfStockDesc stock = stockService.getById(id);
 		return R.data(stock);
 	}
+
 }

+ 98 - 0
blade-service/blade-factory/src/main/java/org/springblade/factory/controller/PcBladeSalesForecastMainController.java

@@ -0,0 +1,98 @@
+package org.springblade.factory.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springblade.factory.entity.PcBladeSalesForecastMain;
+import org.springblade.factory.service.PcBladeSalesForecastMainService;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import java.util.Map;
+
+/**
+ * 销售预测主表 前端控制器
+ *
+ * @author yourname
+ * @since 2025-09-10
+ */
+@RestController
+@RequestMapping("/api/factory/sales-forecast-main")
+@AllArgsConstructor
+public class PcBladeSalesForecastMainController {
+
+
+	private final PcBladeSalesForecastMainService salesForecastMainService;
+
+	/**
+	 * 销售预测主表列表
+	 */
+	@GetMapping
+	@ApiOperation(value = "销售预测主表列表", notes = "")
+	public R<IPage<PcBladeSalesForecastMain>> list(
+		@ApiIgnore @RequestParam Map<String, Object> params,
+		Query query,
+		PcBladeSalesForecastMain pcBladeSalesForecastMain) {
+		// 1. 构建基础查询条件
+		QueryWrapper<PcBladeSalesForecastMain> queryWrapper = Condition.getQueryWrapper(params, PcBladeSalesForecastMain.class);
+		// 2. 执行分页查询
+		IPage<PcBladeSalesForecastMain> pages = salesForecastMainService.page(Condition.getPage(query), queryWrapper);
+		// 3. 返回结果
+		return R.data(pages);
+	}
+
+	/**
+	 * 单条查询
+	 */
+	@GetMapping("/{id}")
+	public R<PcBladeSalesForecastMain> get(@PathVariable("id") Long id) {
+		PcBladeSalesForecastMain main = salesForecastMainService.selectPcBladeSalesForecastMainById(id);
+		return R.data(main);
+	}
+
+	/**
+	 * 新增
+	 */
+	@PostMapping
+	public R<Boolean> save(@RequestBody PcBladeSalesForecastMain pcBladeSalesForecastMain) {
+		return R.data(200, salesForecastMainService.insertPcBladeSalesForecastMain(pcBladeSalesForecastMain), "添加成功");
+	}
+
+	/**
+	 * 修改
+	 */
+	@PutMapping
+	public R<Boolean> update(@RequestBody PcBladeSalesForecastMain pcBladeSalesForecastMain) {
+		return R.data(200, salesForecastMainService.updatePcBladeSalesForecastMain(pcBladeSalesForecastMain), "修改成功");
+	}
+
+	/**
+	 * 根据经销商ID查询
+	 */
+	@GetMapping("/by-customer/{customerId}")
+	@ApiOperation(value = "根据经销商ID查询销售预测", notes = "")
+	public R<IPage<PcBladeSalesForecastMain>> getByCustomerId(
+		@PathVariable("customerId") Long customerId,
+		@ApiIgnore Query query) {
+		QueryWrapper<PcBladeSalesForecastMain> queryWrapper = new QueryWrapper<>();
+		queryWrapper.eq("CUSTOMER_ID", customerId)
+			.eq("is_deleted", 0);
+		IPage<PcBladeSalesForecastMain> pages = salesForecastMainService.page(Condition.getPage(query), queryWrapper);
+		return R.data(pages);
+	}
+
+	/**
+	 * 审批操作
+	 */
+	@PutMapping("/approve")
+	@ApiOperation(value = "审批销售预测", notes = "传入ID和审批状态(0未审批 1已通过 2已拒绝)")
+	public R<Boolean> approve(@RequestBody PcBladeSalesForecastMain pcBladeSalesForecastMain) {
+		boolean result = salesForecastMainService.approve(pcBladeSalesForecastMain);
+		return R.data(200, result, result ? "审批成功" : "审批失败");
+	}
+}

+ 16 - 0
blade-service/blade-factory/src/main/java/org/springblade/factory/mapper/PcBladeSalesForecastMainMapper.java

@@ -0,0 +1,16 @@
+package org.springblade.factory.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springblade.factory.entity.PcBladeSalesForecastMain;
+
+/**
+ * <p>
+ * 销售预测主表 Mapper 接口
+ * </p>
+ *
+ * @author yourname
+ * @since 2025-09-10
+ */
+public interface PcBladeSalesForecastMainMapper extends BaseMapper<PcBladeSalesForecastMain> {
+
+}

+ 5 - 0
blade-service/blade-factory/src/main/java/org/springblade/factory/mapper/xml/PcBladeSalesForecastMainMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.factory.mapper.xml.PcBladeSalesForecastMainMapper">
+    <!-- 在这里添加自定义的 SQL 映射,如果有的话 -->
+</mapper>

+ 80 - 0
blade-service/blade-factory/src/main/java/org/springblade/factory/service/PcBladeSalesForecastMainService.java

@@ -0,0 +1,80 @@
+package org.springblade.factory.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springblade.core.mp.base.BaseService;
+import org.springblade.factory.entity.PcBladeSalesForecastMain;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 销售预测主表 服务类
+ * </p>
+ *
+ * @author yourname
+ * @since 2025-09-10
+ */
+public interface PcBladeSalesForecastMainService extends BaseService<PcBladeSalesForecastMain> {
+
+	/**
+	 * 根据ID查询销售预测主表
+	 * @param id 主键ID
+	 * @return PcBladeSalesForecastMain
+	 */
+	PcBladeSalesForecastMain selectPcBladeSalesForecastMainById(Long id);
+
+	/**
+	 * 新增销售预测主表
+	 * @param pcBladeSalesForecastMain 实体对象
+	 * @return 是否成功
+	 */
+	boolean insertPcBladeSalesForecastMain(PcBladeSalesForecastMain pcBladeSalesForecastMain);
+
+	/**
+	 * 修改销售预测主表
+	 * @param pcBladeSalesForecastMain 实体对象
+	 * @return 是否成功
+	 */
+	boolean updatePcBladeSalesForecastMain(PcBladeSalesForecastMain pcBladeSalesForecastMain);
+
+	/**
+	 * 审批销售预测
+	 * @param pcBladeSalesForecastMain 包含ID和审批状态的实体
+	 * @return 是否成功
+	 */
+	boolean approve(PcBladeSalesForecastMain pcBladeSalesForecastMain);
+
+
+	/**
+	 * 获取列表,和明细列表 --分页
+	 * @param page
+	 * @param queryWrapper
+	 * @return
+	 */
+	IPage<PcBladeSalesForecastMain> pagePro(IPage<PcBladeSalesForecastMain> page, QueryWrapper<PcBladeSalesForecastMain> queryWrapper);
+
+
+	/**
+	 * 批量添加销售预测数据
+	 * @param pcBladeSalesForecastMain
+	 * @return
+	 */
+	boolean batchAdd(PcBladeSalesForecastMain pcBladeSalesForecastMain);
+
+	/**
+	 * 批量修改销售预测数据
+	 * @param pcBladeSalesForecastMain
+	 * @return
+	 */
+	boolean batchUpdate(PcBladeSalesForecastMain pcBladeSalesForecastMain);
+
+
+	/**
+	 * 批量删除销售预测数据
+	 * @param pcBladeSalesForecastMain
+	 * @return
+	 */
+	boolean batchDelete(PcBladeSalesForecastMain pcBladeSalesForecastMain);
+
+}

+ 2 - 0
blade-service/blade-factory/src/main/java/org/springblade/factory/service/PcBladeSalesForecastSummaryService.java

@@ -42,7 +42,9 @@ public interface PcBladeSalesForecastSummaryService extends BaseService<PcBladeS
 	boolean updatePcBladeSalesForecastSummary(PcBladeSalesForecastSummary pcBladeSalesForecastSummary);
 
 
+	boolean saveBatch(List<PcBladeSalesForecastSummary> pcBladeSalesForecastSummaryList);
 
+	boolean updateById(List<PcBladeSalesForecastSummary> pcBladeSalesForecastSummaryList);
 
 
 

+ 310 - 0
blade-service/blade-factory/src/main/java/org/springblade/factory/service/impl/PcBladeSalesForecastMainServiceImpl.java

@@ -0,0 +1,310 @@
+package org.springblade.factory.service.impl;
+
+import com.alibaba.excel.util.CollectionUtils;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.mp.base.BaseServiceImpl;
+import org.springblade.core.secure.utils.AuthUtil;
+import org.springblade.factory.entity.PcBladeSalesForecastMain;
+import org.springblade.factory.entity.PcBladeSalesForecastSummary;
+import org.springblade.factory.entity.ViewCustomerSel;
+import org.springblade.factory.mapper.PcBladeSalesForecastMainMapper;
+import org.springblade.factory.mapper.PcBladeSalesForecastSummaryMapper;
+import org.springblade.factory.service.PcBladeSalesForecastMainService;
+import org.springblade.factory.service.PcBladeSalesForecastSummaryService;
+import org.springblade.factory.service.ZcrmViewCustomerSelService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * <p>
+ * 销售预测主表 服务实现类
+ * </p>
+ *
+ * @author yourname
+ * @since 2025-09-10
+ */
+@Service
+@AllArgsConstructor
+@Slf4j
+public class PcBladeSalesForecastMainServiceImpl extends BaseServiceImpl<PcBladeSalesForecastMainMapper, PcBladeSalesForecastMain> implements PcBladeSalesForecastMainService {
+
+	private final PcBladeSalesForecastSummaryService pcBladeSalesForecastSummaryService;
+	private final ZcrmViewCustomerSelService customerSelService;
+
+
+
+
+	@Override
+	public PcBladeSalesForecastMain selectPcBladeSalesForecastMainById(Long id) {
+		// 1. 查询主表数据
+		PcBladeSalesForecastMain main = baseMapper.selectById(id);
+		if (main == null) {
+			log.warn("销售预测主表数据不存在,ID: {}", id);
+			return null;
+		}
+
+		// 2. 关联查询明细数据
+		try {
+			// 创建查询条件,关联主表ID且状态为有效
+			PcBladeSalesForecastSummary querySummary = new PcBladeSalesForecastSummary();
+			querySummary.setForecastMainId(id);
+			querySummary.setStatus(1); // 假设1表示有效数据
+
+			// 查询明细列表
+			List<PcBladeSalesForecastSummary> summaryList =
+				pcBladeSalesForecastSummaryService.selectPcBladeSalesForecastSummaryList(querySummary);
+
+			// 设置明细列表到主表对象
+			main.setPcBladeSalesForecastSummaryList(summaryList);
+			log.info("查询销售预测主表及明细成功,主表ID: {},明细数量: {}",
+				id, summaryList != null ? summaryList.size() : 0);
+		} catch (Exception e) {
+			log.error("查询销售预测明细数据时发生异常,主表ID: {}", id, e);
+			// 此处不抛出异常,避免因明细查询失败导致主表数据无法返回
+		}
+
+		return main;
+	}
+
+	@Override
+	public boolean insertPcBladeSalesForecastMain(PcBladeSalesForecastMain pcBladeSalesForecastMain) {
+		// 可以在这里添加创建人、创建时间等默认值设置
+		pcBladeSalesForecastMain.setCreateTime(new Date());
+		pcBladeSalesForecastMain.setIsDeleted(0);
+		pcBladeSalesForecastMain.setStatus(1);
+		return save(pcBladeSalesForecastMain);
+	}
+
+	@Override
+	public boolean updatePcBladeSalesForecastMain(PcBladeSalesForecastMain pcBladeSalesForecastMain) {
+		// 设置更新时间
+		pcBladeSalesForecastMain.setUpdateTime(new Date());
+		return updateById(pcBladeSalesForecastMain);
+	}
+
+	@Override
+	public boolean approve(PcBladeSalesForecastMain pcBladeSalesForecastMain) {
+		if (pcBladeSalesForecastMain.getId() == null || pcBladeSalesForecastMain.getApprovalStatus() == null) {
+			return false;
+		}
+
+		UpdateWrapper<PcBladeSalesForecastMain> updateWrapper = new UpdateWrapper<>();
+		updateWrapper.eq("id", pcBladeSalesForecastMain.getId())
+			.set("approval_status", pcBladeSalesForecastMain.getApprovalStatus())
+			.set("approved_time", LocalDateTime.now());
+		return update(updateWrapper);
+	}
+
+	@Override
+	public IPage<PcBladeSalesForecastMain> pagePro(IPage<PcBladeSalesForecastMain> page, QueryWrapper<PcBladeSalesForecastMain> queryWrapper) {
+		// 1. 执行基础分页查询
+		IPage<PcBladeSalesForecastMain> resultPage = this.page(page, queryWrapper);
+
+		// 2. 如果有需要,可以在这里处理查询结果
+		// 例如:关联查询子表数据、计算额外字段等
+		List<PcBladeSalesForecastMain> records = resultPage.getRecords();
+		if (records != null && !records.isEmpty()) {
+			for (PcBladeSalesForecastMain main : records) {
+				// 处理每条记录,例如设置额外计算的字段
+				// TODO 这个需要查询
+				PcBladeSalesForecastSummary pcBladeSalesForecastSummary = new  PcBladeSalesForecastSummary();
+				pcBladeSalesForecastSummary.setForecastMainId(main.getId());
+				pcBladeSalesForecastSummary.setStatus(1);
+				List<PcBladeSalesForecastSummary> pcBladeSalesForecastSummaryList = pcBladeSalesForecastSummaryService.selectPcBladeSalesForecastSummaryList(pcBladeSalesForecastSummary);
+				main.setPcBladeSalesForecastSummaryList(pcBladeSalesForecastSummaryList);
+			}
+		}
+		// 3. 返回处理后的分页结果
+		return resultPage;
+	}
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public boolean batchAdd(PcBladeSalesForecastMain pcBladeSalesForecastMain) {
+		try {
+			// 1. 验证主表数据是否为空
+			if (pcBladeSalesForecastMain == null) {
+				log.error("批量添加失败:主表数据不能为空");
+				return false;
+			}
+
+			// 2. 设置公共字段
+			Long currentUserId = AuthUtil.getUserId();
+
+			// 设置默认审批状态(0-未审批)
+			if (pcBladeSalesForecastMain.getApprovalStatus() == null) {
+				pcBladeSalesForecastMain.setApprovalStatus(0);
+			}
+
+			// 3. 保存主表数据,获取自动生成的ID
+			pcBladeSalesForecastMain.setCustomerId(currentUserId);
+			ViewCustomerSel zcrmViewCustomerSel = customerSelService.selectZcrmViewCustomerSelByCustomerId(pcBladeSalesForecastMain.getCustomerId());
+			pcBladeSalesForecastMain.setCustomerCode(zcrmViewCustomerSel.getCustomerCode());
+			pcBladeSalesForecastMain.setCustomerName(zcrmViewCustomerSel.getCustomerName());
+
+			boolean mainSaved = save(pcBladeSalesForecastMain);
+			if (!mainSaved) {
+				log.error("批量添加失败:主表数据保存失败");
+				return false;
+			}
+
+			// 4. 处理明细表数据
+			List<PcBladeSalesForecastSummary> summaryList = pcBladeSalesForecastMain.getPcBladeSalesForecastSummaryList();
+			if (summaryList != null && !summaryList.isEmpty()) {
+				// 获取主表ID用于关联
+				Long mainId = pcBladeSalesForecastMain.getId();
+				if (mainId == null) {
+					log.error("批量添加失败:主表ID生成失败");
+					// 事务会自动回滚
+					return false;
+				}
+
+				// 设置明细表公共字段和关联ID
+				for (PcBladeSalesForecastSummary summary : summaryList) {
+					// 设置关联主表ID
+					summary.setForecastMainId(mainId);
+
+					// 同步主表的年份、月份和经销商信息
+					summary.setYear(pcBladeSalesForecastMain.getYear());
+					summary.setMonth(pcBladeSalesForecastMain.getMonth());
+					summary.setCustomerId(pcBladeSalesForecastMain.getCustomerId());
+					summary.setCustomerCode(pcBladeSalesForecastMain.getCustomerCode());
+					summary.setCustomerName(pcBladeSalesForecastMain.getCustomerName());
+					summary.setCustomerCode(pcBladeSalesForecastMain.getCustomerCode());
+					summary.setCustomerName(pcBladeSalesForecastMain.getCustomerName());
+					summary.setCustomerId(pcBladeSalesForecastMain.getCustomerId());
+
+					// 设置默认审批状态
+					if (summary.getApprovalStatus() == null) {
+						summary.setApprovalStatus(0);
+					}
+				}
+
+				// 批量保存明细表
+				boolean summarySaved = pcBladeSalesForecastSummaryService.saveBatch(summaryList);
+				if (!summarySaved) {
+					log.error("批量添加失败:明细表数据保存失败");
+					return false;
+				}
+			}
+
+			// 5. 所有操作成功
+			return true;
+
+		} catch (Exception e) {
+			log.error("批量添加销售预测数据失败", e);
+			// 发生异常时事务会自动回滚
+			return false;
+		}
+	}
+
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public boolean batchUpdate(PcBladeSalesForecastMain main) {
+		try {
+			// 1. 验证主表数据及ID
+			if (main == null || main.getId() == null) {
+				log.error("批量修改失败:主表数据或ID不能为空");
+				return false;
+			}
+
+			// 3. 更新主表数据
+			boolean mainUpdated = updateById(main);
+			if (!mainUpdated) {
+				log.error("批量修改失败:主表数据更新失败,主表ID: {}", main.getId());
+				return false;
+			}
+
+			// 4. 处理明细表数据
+			List<PcBladeSalesForecastSummary> summaryList = main.getPcBladeSalesForecastSummaryList();
+			if (summaryList != null && !summaryList.isEmpty()) {
+				Long mainId = main.getId();
+
+				// 遍历处理每条明细
+				for (PcBladeSalesForecastSummary summary : summaryList) {
+					// 验证明细ID
+					if (summary.getId() == null) {
+						log.warn("跳过无ID的明细表数据,主表ID: {}", mainId);
+						continue;
+					}
+
+					// 确保关联关系正确
+					summary.setForecastMainId(mainId);
+
+					// 更新明细数据
+					boolean summaryUpdated = pcBladeSalesForecastSummaryService.updateById(summary);
+					if (!summaryUpdated) {
+						log.error("明细表数据更新失败,明细ID: {}", summary.getId());
+						return false;
+					}
+				}
+
+				log.info("明细表数据更新完成,主表ID: {},共更新{}条明细",
+					mainId, summaryList.size());
+			}
+
+			log.info("主表及明细表数据批量修改成功,主表ID: {}", main.getId());
+			return true;
+
+		} catch (Exception e) {
+			log.error("批量修改销售预测数据发生异常", e);
+			// 事务自动回滚
+			return false;
+		}
+	}
+
+	/**
+	 * 	批量软删除销售预测数据(主表+明细表)
+	 * 	假设实体类使用了MyBatis-Plus的逻辑删除注解@TableLogic
+	 * @param pcBladeSalesForecastMain
+	 * @return
+	 */
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public boolean batchDelete(PcBladeSalesForecastMain pcBladeSalesForecastMain) {
+		// 1. 验证参数
+		if (pcBladeSalesForecastMain == null || pcBladeSalesForecastMain.getId() == null) {
+			log.warn("批量删除失败:主表ID列表为空");
+			return false;
+		}
+
+		try {
+			// 2. 先删除关联的明细表数据
+			QueryWrapper<PcBladeSalesForecastSummary> summaryQuery = new QueryWrapper<>();
+			summaryQuery.in("forecast_main_id", pcBladeSalesForecastMain.getId());
+			boolean summaryDeleted = pcBladeSalesForecastSummaryService.remove(summaryQuery);
+
+			if (!summaryDeleted) {
+				log.warn("明细表数据删除失败,可能无对应明细记录");
+				// 这里不直接返回false,因为可能确实没有明细数据
+			}
+
+			// 3. 再删除主表数据(逻辑删除)
+			boolean mainDeleted = removeById(pcBladeSalesForecastMain.getId());
+			if (!mainDeleted) {
+				log.error("主表数据批量删除失败");
+				return false;
+			}
+
+			// 4. 记录删除结果
+			log.info("批量软删除销售预测数据成功,共处理{}条主表记录", pcBladeSalesForecastMain.getPcBladeSalesForecastSummaryList().size());
+			return true;
+
+		} catch (Exception e) {
+			log.error("批量软删除销售预测数据时发生异常", e);
+			// 事务会自动回滚
+			return false;
+		}
+	}
+
+}
+

+ 100 - 0
blade-service/blade-factory/src/main/java/org/springblade/factory/service/impl/PcBladeSalesForecastSummaryServiceImpl.java

@@ -4,11 +4,13 @@ import com.alibaba.cloud.commons.lang.StringUtils;
 import com.alibaba.excel.EasyExcel;
 import com.alibaba.excel.context.AnalysisContext;
 import com.alibaba.excel.event.AnalysisEventListener;
+import com.alibaba.excel.util.CollectionUtils;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.springblade.core.mp.base.BaseServiceImpl;
@@ -42,6 +44,7 @@ import java.util.concurrent.ExecutionException;
 
 @Service
 @AllArgsConstructor
+@Slf4j
 public class PcBladeSalesForecastSummaryServiceImpl extends BaseServiceImpl<PcBladeSalesForecastSummaryMapper, PcBladeSalesForecastSummary> implements PcBladeSalesForecastSummaryService {
 
 	private PcBladeSalesForecastSummaryMapper forecastMapper;
@@ -69,6 +72,103 @@ public class PcBladeSalesForecastSummaryServiceImpl extends BaseServiceImpl<PcBl
 	}
 
 
+	/**
+	 * 批量保存销售预测明细表数据
+	 *
+	 * @param pcBladeSalesForecastSummaryList 销售预测明细表数据列表
+	 * @return 是否保存成功
+	 */
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public boolean saveBatch(List<PcBladeSalesForecastSummary> pcBladeSalesForecastSummaryList) {
+		// 1. 验证参数
+		if (CollectionUtils.isEmpty(pcBladeSalesForecastSummaryList)) {
+			log.warn("批量保存失败:明细表数据列表为空");
+			return false;
+		}
+
+		try {
+			int total = pcBladeSalesForecastSummaryList.size();
+			log.info("开始批量保存销售预测明细表数据,共{}条记录", total);
+
+			// 2. 不限制批次,直接保存全部数据
+			boolean success = super.saveBatch(pcBladeSalesForecastSummaryList);
+
+			if (success) {
+				log.info("全部销售预测明细表数据批量保存成功,共{}条记录", total);
+				return true;
+			} else {
+				log.error("批量保存失败,所有数据未成功插入");
+				return false;
+			}
+
+		} catch (Exception e) {
+			log.error("批量保存销售预测明细表数据时发生异常", e);
+			// 事务会自动回滚
+			return false;
+		}
+	}
+
+	/**
+	 * 批量更新销售预测明细表数据
+	 *
+	 * @param pcBladeSalesForecastSummaryList 销售预测明细表数据列表
+	 * @return 是否更新成功
+	 */
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public boolean updateById(List<PcBladeSalesForecastSummary> pcBladeSalesForecastSummaryList) {
+		// 1. 验证参数
+		if (CollectionUtils.isEmpty(pcBladeSalesForecastSummaryList)) {
+			log.warn("批量更新失败:明细表数据列表为空");
+			return false;
+		}
+
+		try {
+			int total = pcBladeSalesForecastSummaryList.size();
+			int successCount = 0;
+			log.info("开始批量更新销售预测明细表数据,共{}条记录", total);
+
+			// 2. 遍历列表,逐条更新
+			for (PcBladeSalesForecastSummary summary : pcBladeSalesForecastSummaryList) {
+				// 验证ID是否存在
+				if (summary.getId() == null) {
+					log.warn("跳过无ID的明细表数据,无法更新");
+					continue;
+				}
+
+				// 执行更新操作
+				boolean updated = super.updateById(summary);
+				if (updated) {
+					successCount++;
+				} else {
+					log.warn("明细表数据更新失败,明细ID: {}", summary.getId());
+				}
+			}
+
+			// 3. 检查更新结果
+			if (successCount == 0) {
+				log.error("批量更新失败,所有数据未成功更新");
+				return false;
+			}
+
+			log.info("销售预测明细表数据批量更新完成,共{}条记录,成功更新{}条", total, successCount);
+			// 如果有部分更新成功,这里根据业务需求决定返回true还是false
+			// 这里返回true表示至少有一条更新成功
+			return true;
+
+		} catch (Exception e) {
+			log.error("批量更新销售预测明细表数据时发生异常", e);
+			// 事务会自动回滚
+			return false;
+		}
+	}
+
+
+
+
+
+
 
 
 	/* ========== 业务接口 ========== */

+ 19 - 0
blade-service/blade-u9cloud/src/main/java/org/springblade/u9cloud/Test/TestU9cloudController.java

@@ -8,7 +8,10 @@ import org.springblade.core.mp.base.BaseEntity;
 import org.springblade.core.redis.cache.BladeRedis;
 import org.springblade.core.tool.api.R;
 import org.springblade.u9cloud.entity.*;
+import org.springblade.u9cloud.feign.IZcrmViewCustomerSel;
 import org.springblade.u9cloud.service.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
 import org.springframework.core.ParameterizedTypeReference;
 import org.springframework.http.*;
 import org.springframework.web.bind.annotation.*;
@@ -27,6 +30,7 @@ import java.util.*;
 @RestController
 @RequestMapping("/test1")
 @AllArgsConstructor
+@Configuration
 public class TestU9cloudController {
 
 	private final ZcrmViewCustomerSelService zcrmViewCustomerSelService;
@@ -39,6 +43,21 @@ public class TestU9cloudController {
 
 	private BladeRedis bladeRedis;
 
+	@Autowired
+	private IZcrmViewCustomerSel iZcrmViewCustomerSel;
+
+	@PostMapping("/TestZcrmViewCustomerSelAdd")
+	public R<String> TestZcrmViewCustomerSelAdd(@RequestBody ZcrmViewCustomerSel zcrmViewCustomerSel) {
+//		iZcrmViewCustomerSel.u9cloudAdd(zcrmViewCustomerSel)
+		System.out.println(zcrmViewCustomerSel);
+		zcrmViewCustomerSelService.save(zcrmViewCustomerSel);
+		return R.data("nnnnnnnnnnnnnnnnn");
+	}
+
+
+
+
+
 	@GetMapping("/remoteLink")
 	public R<String> remoteLink()
 	{

+ 4 - 1
blade-service/blade-u9cloud/src/main/java/org/springblade/u9cloud/U9cloudApplication.java

@@ -16,7 +16,10 @@ import org.springframework.web.bind.annotation.RestController;
  *
  * @author Chill
  */
-@EnableFeignClients(basePackages = "org.springblade.system.user.feign")
+@EnableFeignClients(basePackages = {
+	"org.springblade.system.user.feign",  // 保留原有的Feign接口包
+	"org.springblade.u9cloud.feign"       // 添加新的Feign接口包(你的IZcrmViewCustomerSel所在包)
+})
 @BladeCloudApplication
 @SpringCloudApplication
 public class U9cloudApplication {

+ 23 - 0
blade-service/blade-u9cloud/src/main/java/org/springblade/u9cloud/config/FeignConfig.java

@@ -0,0 +1,23 @@
+package org.springblade.u9cloud.config;
+
+import org.springblade.core.tool.api.R;
+import org.springblade.u9cloud.entity.ZcrmViewCustomerSel;
+import org.springblade.u9cloud.feign.IZcrmViewCustomerSel;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class FeignConfig {
+
+	// 手动创建Feign接口的Bean(实际项目中不推荐,应让Feign自动生成)
+//	@Bean
+//	public IZcrmViewCustomerSel zcrmViewCustomerSel() {
+//		// 返回一个模拟实现(仅用于测试,避免启动报错)
+//		return new IZcrmViewCustomerSel() {
+//			@Override
+//			public R<String> u9cloudAdd(ZcrmViewCustomerSel zcrmViewCustomerSel) {
+//				return R.data("模拟返回结果");
+//			}
+//		};
+//	}
+}

+ 94 - 0
blade-service/blade-u9cloud/src/main/java/org/springblade/u9cloud/controller/CommonController.java

@@ -0,0 +1,94 @@
+package org.springblade.u9cloud.controller;
+
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springblade.core.tool.api.R;
+import org.springblade.u9cloud.service.*;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * 统一调用所有U9接口获取数据 前端控制器
+ * </p>
+ *
+ * @author your-name
+ * @since 2025-07-30
+ */
+@RestController
+@RequestMapping("/api/common")
+@Api(tags = "销售订单管理")
+@RequiredArgsConstructor // Lombok注解,替代@Autowired注入
+public class CommonController { // 类名规范:首字母大写,改为CommonController
+
+	private final ZcrmViewCustomerSelService zcrmViewCustomerSelService;
+	private final ZcrmViewDepartmentSelService zcrmViewDepartmentSelService;
+	private final ZcrmViewItemSelService zcrmViewItemSelService;
+	private final ZcrmViewOperatorsSelService zcrmViewOperatorsSelService;
+	private final ZcrmViewShipSelService zcrmViewShipSelService;
+	private final ZcrmViewSupplierSelService zcrmViewSupplierSelService;
+	private final ZcrmViewWhqohSelService zcrmViewWhqohSelService;
+
+
+	/**
+	 * 统一执行U9数据同步,事务保证:任一方法失败则全部回滚
+	 */
+	@GetMapping("/unification")
+	@ApiOperation("U9数据统一同步") // 补充Swagger接口描述(可选)
+	@Transactional(rollbackFor = Exception.class) // 明确对所有Exception回滚
+	public R<String> unification() {
+		try {
+			// 1. 执行各服务的数据同步方法,任一方法返回false则抛出异常触发回滚
+			boolean res1 = zcrmViewCustomerSelService.insertBatchCustomers();
+			if (!res1) {
+				throw new RuntimeException("客户数据批量插入失败");
+			}
+
+			boolean res2 = zcrmViewDepartmentSelService.insertBatchDepartments();
+			if (!res2) {
+				throw new RuntimeException("部门数据批量插入失败");
+			}
+
+			boolean res3 = zcrmViewItemSelService.insertBatchItems();
+			if (!res3) {
+				throw new RuntimeException("物料数据批量插入失败");
+			}
+
+			boolean res4 = zcrmViewOperatorsSelService.insertBatchOperators();
+			if (!res4) {
+				throw new RuntimeException("操作员数据批量插入失败");
+			}
+
+			boolean res5 = zcrmViewShipSelService.insertBatchShips();
+			if (!res5) {
+				throw new RuntimeException("物流数据批量插入失败");
+			}
+
+			boolean res6 = zcrmViewSupplierSelService.insertBatchSuppliers();
+			if (!res6) {
+				throw new RuntimeException("供应商数据批量插入失败");
+			}
+
+			boolean res7 = zcrmViewWhqohSelService.insertBatchWhqohs();
+			if (!res7) {
+				throw new RuntimeException("库存数据批量插入失败");
+			}
+
+			// 2. 所有方法执行成功,返回成功结果
+			return R.data("所有U9数据同步执行成功");
+
+		} catch (Exception e) {
+			// 3. 捕获所有异常,打印日志(便于排查),并返回失败信息
+			// 建议使用日志框架(如Slf4j)打印异常栈,此处示例用System.err
+			System.err.println("U9数据同步失败,触发事务回滚:" + e.getMessage());
+			e.printStackTrace(); // 生产环境建议用日志框架(如log.error("", e))
+
+			// 返回具体失败原因,便于前端排查
+			return R.fail("U9数据同步失败:" + e.getMessage());
+		}
+	}
+}

+ 15 - 0
blade-service/blade-u9cloud/src/main/java/org/springblade/u9cloud/controller/ZcrmViewCustomerSelController.java

@@ -4,7 +4,9 @@ import lombok.AllArgsConstructor;
 import lombok.RequiredArgsConstructor;
 import org.springblade.core.tool.api.R;
 import org.springblade.u9cloud.entity.ZcrmViewCustomerSel;
+import org.springblade.u9cloud.feign.IZcrmViewCustomerSel;
 import org.springblade.u9cloud.service.ZcrmViewCustomerSelService;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 /**
@@ -18,6 +20,7 @@ import org.springframework.web.bind.annotation.*;
 @RestController
 @RequestMapping("/api/viewCustomerSel")
 @AllArgsConstructor
+
 public class ZcrmViewCustomerSelController {
 
 	private final ZcrmViewCustomerSelService zcrmViewCustomerSelService;
@@ -36,4 +39,16 @@ public class ZcrmViewCustomerSelController {
 			return R.data("执行失败");
 		}
 	}
+
+
+	@PostMapping("/TestZcrmViewCustomerSelAdd")
+	public R<String> TestZcrmViewCustomerSelAdd(@RequestBody ZcrmViewCustomerSel zcrmViewCustomerSel) {
+		boolean res = zcrmViewCustomerSelService.save(zcrmViewCustomerSel);
+		if (res) {
+			return R.data("执行成功");
+		} else {
+			return R.data("执行失败");
+		}
+	}
+
 }

+ 7 - 0
blade-service/blade-u9cloud/src/main/java/org/springblade/u9cloud/service/ZcrmViewCustomerSelService.java

@@ -1,6 +1,7 @@
 package org.springblade.u9cloud.service;
 
 import org.springblade.core.mp.base.BaseService;
+import org.springblade.core.tool.api.R;
 import org.springblade.u9cloud.entity.ZcrmViewCustomerSel;
 
 import javax.validation.constraints.NotEmpty;
@@ -33,4 +34,10 @@ public interface ZcrmViewCustomerSelService extends BaseService<ZcrmViewCustomer
 
 
 	boolean insertBatchCustomers(List<ZcrmViewCustomerSel> customers);
+
+
+	R<String> u9cloudAdd(ZcrmViewCustomerSel zcrmViewCustomerSel);
+
+
+
 }

+ 17 - 0
blade-service/blade-u9cloud/src/main/java/org/springblade/u9cloud/service/impl/ZcrmViewCustomerSelServiceImpl.java

@@ -135,4 +135,21 @@ public class ZcrmViewCustomerSelServiceImpl extends BaseServiceImpl<ZcrmViewCust
 		}
 		return res;
 	}
+
+	/**
+	 * 内部调用
+	 */
+	@Override
+	public R<String> u9cloudAdd(ZcrmViewCustomerSel zcrmViewCustomerSel) {
+		boolean res = this.save(zcrmViewCustomerSel);
+		if (res) {
+			return R.data("保存成功");
+		} else {
+			return R.data("保存失败");
+		}
+	}
+
+
+
+
 }