Преглед на файлове

导入导出EXCEL,经销商获取并保存到缓存接口

bai преди 1 седмица
родител
ревизия
7820300fd3

+ 44 - 0
blade-service/blade-factory/src/main/java/org/springblade/factory/api/controller/CommonController.java

@@ -0,0 +1,44 @@
+package org.springblade.factory.api.controller;
+
+
+import lombok.AllArgsConstructor;
+import org.springblade.core.secure.utils.AuthUtil;
+import org.springblade.core.tool.api.R;
+import org.springblade.factory.entity.ViewCustomerSel;
+import org.springblade.factory.service.ZcrmViewCustomerSelService;
+import org.springblade.u9cloud.entity.ZcrmViewCustomerSel;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 公共接口 控制器
+ *
+ * @author horizon
+ * @since 2025-08-05
+ */
+@RestController
+@RequestMapping("/api/factory/common")
+@AllArgsConstructor
+public class CommonController {
+
+	private final ZcrmViewCustomerSelService zcrmViewCustomerSelService;
+
+
+	/**
+	 * 根据 Customer_ID 获取一条数据,并存入缓存
+	 * @param
+	 * @return
+	 */
+	@GetMapping("/getCustomerSel")
+	public R<ViewCustomerSel> getCustomerSel(Long customer_id) {
+		if (customer_id != null) {
+			System.out.println(customer_id);
+			ViewCustomerSel viewCustomerSel = zcrmViewCustomerSelService.selectZcrmViewCustomerSelByCustomerId(customer_id);
+			return R.data(viewCustomerSel);
+		}
+		Long id = AuthUtil.getUserId();
+		System.out.println(id);
+		ViewCustomerSel viewCustomerSel = zcrmViewCustomerSelService.selectZcrmViewCustomerSelByCustomerId(id);
+		return R.data(viewCustomerSel);
+	}
+
+}

+ 0 - 11
blade-service/blade-factory/src/main/java/org/springblade/factory/api/controller/SalesForecastSummaryController.java

@@ -12,7 +12,6 @@ import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.tool.api.R;
 import org.springblade.factory.entity.PcBladeSalesForecastSummary;
 import org.springblade.factory.service.PcBladeSalesForecastSummaryService;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 import springfox.documentation.annotations.ApiIgnore;
@@ -36,19 +35,9 @@ import java.util.Map;
 public class SalesForecastSummaryController {
 
 	/* ========== 经销商提报 ========== */
-
-	// TODO 业务逻辑描述
-
-	// TODO 首先查询当前日期是否超过21日,如果超过21就不能再提报预测了
-
-	// TODO 如果没超过21号,就查询一下数据库是否已经进行了预测提报,如果已提报了,就返回【已经提报了】更新已经提报的信息
-
-	// TODO 如果没有提报就新增一条数据
-
 	private final PcBladeSalesForecastSummaryService forecastService;
 
 
-
 	/**
 	 * 销售预测汇总列表
 	 */

+ 0 - 1
blade-service/blade-factory/src/main/java/org/springblade/factory/api/controller/SalesOrderController.java

@@ -6,7 +6,6 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
-import org.apache.poi.ss.formula.functions.T;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
 import org.springblade.core.tool.api.R;

+ 6 - 0
blade-service/blade-factory/src/main/java/org/springblade/factory/mapper/PcBladeSalesForecastSummaryMapper.java

@@ -4,6 +4,12 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 import org.springblade.factory.entity.PcBladeSalesForecastSummary;
 
+import java.util.List;
+
 @Mapper
 public interface PcBladeSalesForecastSummaryMapper extends BaseMapper<PcBladeSalesForecastSummary> {
+
+	int deleteByExample(PcBladeSalesForecastSummary example);
+	int batchInsert(List<PcBladeSalesForecastSummary> list);
+
 }

+ 11 - 0
blade-service/blade-factory/src/main/java/org/springblade/factory/service/ZcrmViewCustomerSelService.java

@@ -33,4 +33,15 @@ public interface ZcrmViewCustomerSelService extends BaseService<ViewCustomerSel>
 	 * @return
 	 */
 	boolean updateZcrmViewCustomerSel(ViewCustomerSel viewCustomerSel);
+
+
+	/**
+	 * 根据 Customer_ID 获取一条数据,并存入缓存
+	 * @param customerId
+	 * @return
+	 */
+	ViewCustomerSel selectZcrmViewCustomerSelByCustomerId(Long customerId);
+
+
+
 }

+ 181 - 44
blade-service/blade-factory/src/main/java/org/springblade/factory/service/impl/PcBladeSalesForecastSummaryServiceImpl.java

@@ -1,9 +1,16 @@
 package org.springblade.factory.service.impl;
 
+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.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 org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.springblade.core.mp.base.BaseServiceImpl;
 import org.springblade.core.mp.support.Query;
 import org.springblade.core.secure.utils.AuthUtil;
@@ -15,6 +22,11 @@ import org.springblade.factory.service.PcBladeSalesForecastSummaryService;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
+
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.time.temporal.TemporalAdjusters;
 
 import javax.servlet.http.HttpServletResponse;
@@ -22,13 +34,19 @@ import java.io.IOException;
 import java.time.DateTimeException;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
+import java.util.concurrent.ExecutionException;
 
 @Service
+@AllArgsConstructor
 public class PcBladeSalesForecastSummaryServiceImpl extends BaseServiceImpl<PcBladeSalesForecastSummaryMapper, PcBladeSalesForecastSummary> implements PcBladeSalesForecastSummaryService {
 
+	private PcBladeSalesForecastSummaryMapper forecastMapper;
+
+
 	@Override
 	public List<PcBladeSalesForecastSummary> selectPcBladeSalesForecastSummaryList(PcBladeSalesForecastSummary pcBladeSalesForecastSummary) {
 		QueryWrapper<PcBladeSalesForecastSummary> queryWrapper = new QueryWrapper<>();
@@ -234,27 +252,67 @@ public class PcBladeSalesForecastSummaryServiceImpl extends BaseServiceImpl<PcBl
 	 */
 	@Override
 	public void exportExcelTemplate(HttpServletResponse response) throws IOException {
+		// 创建Excel工作簿
+		Workbook workbook = new XSSFWorkbook();
+		// 创建工作表
+		Sheet sheet = workbook.createSheet("销售预测模板");
+
+		// 创建表头行
+		Row headerRow = sheet.createRow(0);
+
+		// 定义表头内容(与实体类字段对应)
+		String[] headers = {
+			"年份", "月份", "经销商ID", "经销商编码", "经销商名称",
+			"品牌ID", "品牌编码", "品牌名称", "物料ID", "物料编码",
+			"物料名称", "规格", "花纹", "预测数量"
+		};
+
+		// 创建单元格样式
+
+		CellStyle headerStyle = workbook.createCellStyle();
+		Font font = workbook.createFont();
+		font.setBold(true);
+		headerStyle.setFont(font);
+		headerStyle.setBorderTop(BorderStyle.THIN);
+		headerStyle.setBorderBottom(BorderStyle.THIN);
+		headerStyle.setBorderLeft(BorderStyle.THIN);
+		headerStyle.setBorderRight(BorderStyle.THIN);
+		headerStyle.setAlignment(HorizontalAlignment.CENTER);
+
+		// 设置表头
+		for (int i = 0; i < headers.length; i++) {
+			Cell cell = headerRow.createCell(i);
+			cell.setCellValue(headers[i]);
+			cell.setCellStyle(headerStyle);
+			// 自动调整列宽
+			sheet.autoSizeColumn(i);
+		}
+
+		// 添加一行示例数据(可选)
+		Row exampleRow = sheet.createRow(1);
+		exampleRow.createCell(0).setCellValue(2023);
+		exampleRow.createCell(1).setCellValue(10);
+		exampleRow.createCell(3).setCellValue("CUST001");
+		exampleRow.createCell(4).setCellValue("示例经销商");
+		exampleRow.createCell(6).setCellValue("BRAND001");
+		exampleRow.createCell(7).setCellValue("示例品牌");
+		exampleRow.createCell(9).setCellValue("ITEM001");
+		exampleRow.createCell(10).setCellValue("示例物料");
+		exampleRow.createCell(11).setCellValue("规格示例");
+		exampleRow.createCell(12).setCellValue("花纹示例");
+		exampleRow.createCell(13).setCellValue(100);
+
 		// 设置响应头
 		response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
-		response.setHeader("Content-Disposition", "attachment;filename=销售预测模板.xlsx");
-
-		// 实际项目中使用EasyExcel或POI生成模板
-		// 模板应包含需要填写的字段:年份、月份、品牌信息、物料信息、预测数量等
-		// 注意:主键ID、创建时间、更新时间等系统生成字段不需要在模板中出现
-
-		// 以下为示例代码框架
-        /*
-        List<PcBladeSalesForecastSummary> templateData = new ArrayList<>();
-        PcBladeSalesForecastSummary template = new PcBladeSalesForecastSummary();
-        template.setYear(LocalDate.now().getYear());
-        template.setMonth(LocalDate.now().getMonthValue());
-        // 设置其他模板提示信息
-        templateData.add(template);
-
-        EasyExcel.write(response.getOutputStream(), PcBladeSalesForecastSummary.class)
-                .sheet("销售预测")
-                .doWrite(templateData);
-        */
+		String fileName = URLEncoder.encode("销售预测模板.xlsx", StandardCharsets.UTF_8.name());
+		response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + fileName);
+
+		// 写入响应输出流
+		try (OutputStream os = response.getOutputStream()) {
+			workbook.write(os);
+		} finally {
+			workbook.close();
+		}
 	}
 
 	/**
@@ -268,33 +326,112 @@ public class PcBladeSalesForecastSummaryServiceImpl extends BaseServiceImpl<PcBl
 			return R.fail("本月21日后不能再提报预测");
 		}
 
+		// 检查文件是否为空
+		if (file.isEmpty()) {
+			return R.fail("导入文件不能为空");
+		}
+
+		// 检查文件格式
+		String fileName = file.getOriginalFilename();
+		if (fileName == null || (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls"))) {
+			return R.fail("请上传Excel格式的文件");
+		}
+
 		Long loginUserId = AuthUtil.getUserId();
+		if (loginUserId == null) {
+			return R.fail("用户未登录");
+		}
+
+		// 使用EasyExcel读取Excel文件
+		List<PcBladeSalesForecastSummary> forecasts = EasyExcel.read(file.getInputStream())
+			.head(PcBladeSalesForecastSummary.class)
+			.registerReadListener(new AnalysisEventListener<PcBladeSalesForecastSummary>() {
+				// 可以在这里添加逐行验证逻辑
+				@Override
+				public void invoke(PcBladeSalesForecastSummary data, AnalysisContext context) {
+
+				}
+
+				@Override
+				public void doAfterAllAnalysed(AnalysisContext context) {
+					// 所有数据解析完成后执行
+				}
+			})
+			.sheet()
+			.doReadSync();
+
+		// 验证导入的数据
+		if (forecasts.isEmpty()) {
+			return R.fail("导入数据为空");
+		}
+
+		// 数据验证和处理
+		List<String> errorMessages = new ArrayList<>();
+
+		for (int i = 0; i < forecasts.size(); i++) {
+			PcBladeSalesForecastSummary forecast = forecasts.get(i);
+			int rowNum = i + 2; // 行号从2开始(表头+1)
+
+			// 基本数据验证
+			if (forecast.getYear() == null) {
+				errorMessages.add("第" + rowNum + "行:年份不能为空");
+			}
+
+			if (forecast.getMonth() == null || forecast.getMonth() < 1 || forecast.getMonth() > 12) {
+				errorMessages.add("第" + rowNum + "行:月份格式不正确");
+			}
 
-		// 这里实现Excel数据导入逻辑
-		// 使用EasyExcel或POI解析Excel文件
-        /*
-        List<PcBladeSalesForecastSummary> forecasts = EasyExcel.read(file.getInputStream())
-                .head(PcBladeSalesForecastSummary.class)
-                .sheet()
-                .doReadSync();
-
-        // 验证导入的数据
-        if (forecasts.isEmpty()) {
-            return R.fail("导入数据为空");
-        }
-
-        // 统一设置经销商ID为登录用户ID,防止冒充填报
-        for (PcBladeSalesForecastSummary forecast : forecasts) {
-            forecast.setCustomerId(loginUserId);
-            // 清除可能手动填写的ID,由系统生成
-            forecast.setId(null);
-        }
-
-        // 调用批量保存方法
-        return batchSaveOrUpdateForecasts(forecasts);
-        */
-
-		return R.success("导入成功");
+			if (StringUtils.isEmpty(forecast.getItemCode())) {
+				errorMessages.add("第" + rowNum + "行:物料编码不能为空");
+			}
+
+			if (forecast.getForecastQuantity() == null || forecast.getForecastQuantity().compareTo(BigDecimal.ZERO) <= 0) {
+				errorMessages.add("第" + rowNum + "行:预测数量必须大于0");
+			}
+
+			// 设置系统字段,覆盖可能手动填写的值
+			forecast.setCustomerId(loginUserId); // 强制设置为当前登录用户ID
+			forecast.setId(null); // 清除ID,由系统生成
+			forecast.setApprovalStatus(0); // 初始化为未审批状态
+			forecast.setCreateTime(new Date());
+			forecast.setCreateUser(AuthUtil.getUserId());
+			forecast.setUpdateTime(new Date());
+			forecast.setUpdateUser(AuthUtil.getUserId());
+
+			// 清除审批相关字段,避免导入时携带
+			forecast.setApprovedBy(null);
+			forecast.setApprovedName(null);
+			forecast.setApprovedTime(null);
+		}
+
+		// 如果有验证错误,返回错误信息
+		if (!errorMessages.isEmpty()) {
+			return R.fail("导入数据验证失败:\n" + String.join("\n", errorMessages));
+		}
+
+		// 调用批量保存方法
+		return batchSaveOrUpdateForecastsFun(forecasts);
+	}
+
+	/**
+	 * 批量保存或更新预测数据
+	 */
+	private R<String> batchSaveOrUpdateForecastsFun(List<PcBladeSalesForecastSummary> forecasts) {
+		try {
+			// 先删除当前用户已有的同月份数据,避免重复
+			PcBladeSalesForecastSummary example = new PcBladeSalesForecastSummary();
+			example.setCustomerId(forecasts.get(0).getCustomerId());
+			example.setYear(forecasts.get(0).getYear());
+			example.setMonth(forecasts.get(0).getMonth());
+			forecastMapper.deleteByExample(example);
+
+			// 批量插入新数据
+			forecastMapper.batchInsert(forecasts);
+			return R.success("导入成功,共导入" + forecasts.size() + "条数据");
+		} catch (Exception e) {
+			log.error("批量保存预测数据失败", e);
+			return R.fail("导入失败:" + e.getMessage());
+		}
 	}
 
 	/**

+ 42 - 0
blade-service/blade-factory/src/main/java/org/springblade/factory/service/impl/ZcrmViewCustomerSelServiceImpl.java

@@ -1,7 +1,11 @@
 package org.springblade.factory.service.impl;
 
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import lombok.AllArgsConstructor;
+import org.springblade.common.utils.RedisUtil;
 import org.springblade.core.mp.base.BaseServiceImpl;
+import org.springblade.core.redis.cache.BladeRedis;
 import org.springblade.factory.entity.ViewCustomerSel;
 import org.springblade.factory.mapper.ZcrmViewCustomerSelMapper;
 import org.springblade.factory.service.ZcrmViewCustomerSelService;
@@ -10,8 +14,13 @@ import org.springframework.stereotype.Service;
 import java.util.List;
 
 @Service
+@AllArgsConstructor
 public class ZcrmViewCustomerSelServiceImpl extends BaseServiceImpl<ZcrmViewCustomerSelMapper, ViewCustomerSel> implements ZcrmViewCustomerSelService {
 
+
+	private final BladeRedis bladeRedis;
+
+
 	@Override
 	public List<ViewCustomerSel> selectZcrmViewCustomerSelList(ViewCustomerSel viewCustomerSel) {
 		QueryWrapper<ViewCustomerSel> queryWrapper = new QueryWrapper<>();
@@ -32,4 +41,37 @@ public class ZcrmViewCustomerSelServiceImpl extends BaseServiceImpl<ZcrmViewCust
 	public boolean updateZcrmViewCustomerSel(ViewCustomerSel viewCustomerSel) {
 		return this.updateById(viewCustomerSel);
 	}
+
+	@Override
+	public ViewCustomerSel selectZcrmViewCustomerSelByCustomerId(Long customerId) {
+		if (customerId == null) {
+			return null;
+		}
+
+		String cacheKey = "customer:sel:" + customerId;
+		System.out.println(cacheKey);
+		// 先从缓存获取
+		if (bladeRedis.get(cacheKey) != null) {
+			String viewCustomerSelString = bladeRedis.get(cacheKey);
+			// 将JSON字符串转换为对象
+			return JSON.parseObject(viewCustomerSelString, ViewCustomerSel.class);
+		}
+
+		// 缓存未命中则查询数据库
+		QueryWrapper<ViewCustomerSel> queryWrapper = new QueryWrapper<>();
+		queryWrapper.eq("customer_id", customerId);
+		ViewCustomerSel customerSel = this.getOne(queryWrapper);
+
+		// 查询结果不为空则存入缓存
+		if (customerSel != null) {
+			// 将对象转换为JSON字符串存储
+			String customerSelJson = JSON.toJSONString(customerSel);
+			bladeRedis.set(cacheKey, customerSelJson);
+		}
+
+		return customerSel;
+	}
+
+
+
 }